### 详细描述

Cobalt/POSIX 进程调度。

title: Cobalt/Process scheduling

---
### 函数文档

### sched_get_priority_max()

> int sched_get_priority_max (int policy)

获取指定调度策略的最大优先级。

该服务返回调度策略 **policy** 的最大优先级。

**参数**:
- **policy**: 调度策略。

**返回值**:
- 成功时返回 **0**。
- 出错时返回 **-1** 并设置 errno：
    - **EINVAL**: **policy** 无效。

**标签**:
- `thread-unrestricted`，`switch-secondary`

**注意**:
获取 `SCHED_FIFO`、`SCHED_RR` 或任何 xkernel 特定策略的最大优先级级别不会导致模式切换。**policy** 的任何其他值可能会将调用者切换到次级模式。

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <errno.h>

int main() {
    int policy = SCHED_FIFO; // 可以选择 SCHED_OTHER, SCHED_RR, SCHED_FIFO
    int max_priority;

    // 获取指定调度策略的最大优先级
    max_priority = sched_get_priority_max(policy);
    
    // 检查返回值
    if (max_priority == -1) {
        perror("sched_get_priority_max");
        exit(EXIT_FAILURE);
    }

    printf("The maximum priority for policy %d is: %d\n", policy, max_priority);
    
    return 0;
}
```


#### sched_get_priority_max_ex()

> int sched_get_priority_max_ex (int policy)

获取指定调度策略的扩展最大优先级。

该服务返回调度策略 **policy** 的最大优先级，反映任何 Cobalt 对标准类的扩展。

**参数**:
- **policy**: 调度策略。

**返回值**:
- 成功时返回 **0**。
- 出错时返回 **-1** 并设置 errno：
    - **EINVAL**: **policy** 无效。

**标签**:
- `thread-unrestricted`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <errno.h>

int main() {
    int policy = SCHED_FIFO; // 可以选择 SCHED_OTHER, SCHED_RR, SCHED_FIFO
    int max_priority;

    // 获取指定调度策略的最大优先级
    max_priority = sched_get_priority_max_ex(policy);
    
    // 检查返回值
    if (max_priority == -1) {
        perror("sched_get_priority_max_ex");
        exit(EXIT_FAILURE);
    }

    printf("The maximum priority for policy %d is: %d\n", policy, max_priority);
    
    return 0;
}
```


#### sched_get_priority_min()

> int sched_get_priority_min (int policy)

获取指定调度策略的最小优先级。

该服务返回调度策略 **policy** 的最小优先级。

**参数**:
- **policy**: 调度策略。

**返回值**:
- 成功时返回 **0**。
- 出错时返回 **-1** 并设置 errno：
    - **EINVAL**: **policy** 无效。

**标签**:
- `thread-unrestricted`，`switch-secondary`

**注意**:
获取 **SCHED_FIFO**、**SCHED_RR** 或任何 xkernel 特定策略的最小优先级级别不会导致模式切换。**policy** 的任何其他值可能会将调用者切换到次级模式。

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <errno.h>

int main() {
    int policy = SCHED_FIFO; // 可以选择 SCHED_OTHER, SCHED_RR, SCHED_FIFO
    int min_priority;

    // 获取指定调度策略的最大优先级
    min_priority = sched_get_priority_min(policy);
    
    // 检查返回值
    if (min_priority == -1) {
        perror("sched_get_priority_min");
        exit(EXIT_FAILURE);
    }

    printf("The minimum priority for policy %d is: %d\n", policy, min_priority);
    
    return 0;
}
```
---

### sched_get_priority_min_ex()

> int sched_get_priority_min_ex (int policy)

获取指定调度策略的扩展最小优先级。

该服务返回调度策略 **policy** 的最小优先级，反映任何 Cobalt 对标准类的扩展。

**参数**:
- **policy**: 调度策略。

**返回值**:
- 成功时返回 **0**。
- 出错时返回 **-1** 并设置 errno：
    - **EINVAL**: **policy** 无效。

**标签**:
- `thread-unrestricted`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <errno.h>

int main() {
    int policy = SCHED_FIFO; // 可以选择 SCHED_OTHER, SCHED_RR, SCHED_FIFO
    int min_priority;

    // 获取指定调度策略的最大优先级
    min_priority = sched_get_priority_min_ex(policy);
    
    // 检查返回值
    if (min_priority == -1) {
        perror("sched_get_priority_min_ex");
        exit(EXIT_FAILURE);
    }

    printf("The minimum priority for policy %d is: %d\n", policy, min_priority);
    
    return 0;
}
```

---

### sched_getconfig_np()

> ssize_t sched_getconfig_np (int cpu, int policy, union sched_config *config, size_t *len_r)

检索特定 CPU 的调度策略设置。

配置严格地局限于目标 **cpu**，并且可能与其他处理器不同。

**参数**:
- **cpu**: 要检索配置的处理器。
- **policy**: 配置数据适用的调度策略。目前，仅 `SCHED_TP` 和 `SCHED_QUOTA` 是有效输入。
- **config**: 一个指向内存区域的指针，该区域在调用成功时接收配置设置。

**SCHED_TP 具体细节**:
成功返回时，**config->quota.tp** 包含 **cpu** 上活动的 TP 调度。

**SCHED_QUOTA 具体细节**:
进入时，**config->quota.get.tgid** 必须包含要查询的线程组标识符。
成功退出时，**config->quota.info** 包含与 **config->quota.get.tgid** 引用的线程组相关的信息。

**参数**:
- **[in, out] len_r**: 一个指向变量的指针，用于收集返回的配置数据的总长度（以字节为单位）。在请求发出时，该变量必须包含 **config** 中可用的空间量。

**返回值**:
- 成功时返回复制到 **config** 的字节数；
- 出错时返回负错误号：
    - **EINVAL**: **cpu** 无效，或 **policy** 不受当前内核配置支持，或 **len** 无法容纳检索到的配置数据。
    - **ESRCH**，当 **policy** 等于 `SCHED_QUOTA` 时，如果执行操作所需的组标识符无效（即 **config->quota.get.tgid** 无效）。
    - **ENOMEM**: 执行操作时内存不足。
    - **ENOSPC**: **len** 太短。

**标签**:
- `thread-unrestricted`，`switch-primary`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <cobalt/sched.h>

void *thread_function(void *arg) {
    int cpu = 0;  // 目标 CPU
    union sched_config config;
    size_t len;

    // 设置 TP 调度窗口
    config.tp.op = sched_tp_install;
    config.tp.nr_windows = 1;
    
    // 配置1个时间窗口
    config.tp.windows[0].offset.tv_sec = 0;
    config.tp.windows[0].offset.tv_nsec = 10000000;
    config.tp.windows[0].duration.tv_sec = 0;
    config.tp.windows[0].duration.tv_nsec = 10000000;  // 10ms
    config.tp.windows[0].ptid = 2;

    len = sizeof(config.tp);

    // 设置 SCHED_TP 配置
    if (sched_setconfig_np(cpu, SCHED_TP, &config, len) < 0) {
        perror("sched_setconfig_np");
        exit(EXIT_FAILURE);
    }

     // 检索 SCHED_TP 配置
    len = sizeof(config);
    if (sched_getconfig_np(cpu, SCHED_TP, &config, &len) < 0) {
        perror("sched_getconfig_np");
        exit(EXIT_FAILURE);
    }

    printf("Successfully retrieved SCHED_TP configuration for CPU %d\n", cpu);
    printf("Number of windows: %d\n", config.tp.nr_windows);

    // 打印每个时间窗口的信息
    for (int i = 0; i < config.tp.nr_windows; i++) {
        printf("Window %d:\n", i);
        printf("  Offset: %ld.%09ld\n", 
               config.tp.windows[i].offset.tv_sec,
               config.tp.windows[i].offset.tv_nsec);
        printf("  Duration: %ld.%09ld\n", 
               config.tp.windows[i].duration.tv_sec,
               config.tp.windows[i].duration.tv_nsec);
        printf("  Partition ID: %d\n", config.tp.windows[i].ptid);
    }

    // 启动 TP 调度
    config.tp.op = sched_tp_start;
    if (sched_setconfig_np(cpu, SCHED_TP, &config, len) < 0) {
        perror("sched_setconfig_np (start)");
        exit(EXIT_FAILURE);
    }

    printf("Thread running with PID: %d\n", getpid());
    for (int i = 0; i < 3; i++) {
        printf("Thread: %d\n", i);
        sleep(1);
    }

    //停止TP调度并卸载
    config.tp.op = sched_tp_stop;
    if (sched_setconfig_np(cpu, SCHED_TP, &config, len) < 0) {
        perror("sched_setconfig_np (start)");
        exit(EXIT_FAILURE);
    }
    config.tp.op = sched_tp_uninstall;
    if (sched_setconfig_np(cpu, SCHED_TP, &config, len) < 0) {
        perror("sched_setconfig_np (start)");
        exit(EXIT_FAILURE);
    }
    pthread_exit(0);
}

int main() {
    pthread_t thread;

    // 创建线程
    if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
        perror("pthread_create");
        return EXIT_FAILURE;
    }

    // 等待线程结束
    pthread_join(thread, NULL);
    printf("Thread finished.\n");

    return EXIT_SUCCESS;
}
```

---
### sched_setconfig_np()

> int sched_setconfig_np (int cpu, int policy, const union sched_config *config, size_t len)

为特定 CPU 设置调度策略配置。

配置严格地局限于目标 **cpu**，并且可能与其他处理器不同。

**参数**:
- **cpu**: 要加载配置的处理器。
- **policy**: 配置数据适用的调度策略。目前，**SCHED_TP** 和 **SCHED_QUOTA** 是有效的。
- **config**: 一个指向要加载到 **cpu** 上的配置数据的指针，适用于 **policy**。

#### 适用于 SCHED_TP 的设置

此调用根据请求的操作控制 **cpu** 的时间分区。

- **config.tp.op** 指定要执行的操作：
    - **sched_tp_install** 在 **cpu** 上安装一个新的 TP 调度，由 **config.tp.windows[]** 定义。全局时间框架在此请求返回时尚未激活；必须发出 **sched_tp_start** 才能在 **cpu** 上激活时间调度。
    - **sched_tp_uninstall** 从 **cpu** 上移除当前的 TP 调度，释放所有附加资源。如果 **cpu** 上不存在 TP 调度，则此请求无效。
    - **sched_tp_start** 启用 **cpu** 上的时间调度，启动全局时间框架。如果 **cpu** 上不存在 TP 调度，则此操作无效。
    - **sched_tp_stop** 禁用 **cpu** 上的时间调度。不过，当前的 TP 调度不会被卸载，可以通过 **sched_tp_start** 请求稍后重新启动。

**注意**:
- 由于此请求的结果，分配给未调度分区的线程可能会被剥夺 CPU 时间。

#### 适用于 SCHED_QUOTA 的设置

此调用管理在 **cpu** 上运行的线程组，定义每组的配额以限制其 CPU 消耗。

- **config.quota.op** 应定义要执行的操作。有效操作包括：
    - **sched_quota_add** 在 **cpu** 上创建一个新的线程组。新组标识符将在成功时写回到 **info.tgid**。
    - **sched_quota_remove** 删除 **cpu** 上的线程组。组标识符应传递到 **config.quota.remove.tgid**。
    - **sched_quota_set** 更新在 **cpu** 上定义的线程组的调度参数。

**参数**:
- **len**: 配置数据的总长度（以字节为单位）。

**返回值**:
- 成功时返回 **0**；
- 出错时返回错误号：
    - **EINVAL**: **cpu** 无效，或 **policy** 不受当前内核配置支持，或 **len** 无效，或 **config** 包含无效参数。
    - **ENOMEM**: 执行操作时内存不足。
    - **EBUSY**: 当 **policy** 等于 **SCHED_QUOTA** 时，如果尝试删除仍在管理线程的线程组。
    - **ESRCH**: 当 **policy** 等于 **SCHED_QUOTA** 时，如果执行操作所需的组标识符无效。

**标签**:
- `thread-unrestricted`，`switch-primary`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <cobalt/sched.h>

void *thread_function(void *arg) {
    int cpu = 0;  // 目标 CPU
    union sched_config config;
    size_t len;

    // 设置 TP 调度窗口
    config.tp.op = sched_tp_install;
    config.tp.nr_windows = 1;
    
    // 配置1个时间窗口
    config.tp.windows[0].offset.tv_sec = 0;
    config.tp.windows[0].offset.tv_nsec = 0;
    config.tp.windows[0].duration.tv_sec = 0;
    config.tp.windows[0].duration.tv_nsec = 10000000;  // 10ms
    config.tp.windows[0].ptid = 1;

    len = sizeof(config.tp);

    // 设置 SCHED_TP 配置
    if (sched_setconfig_np(cpu, SCHED_TP, &config, len) < 0) {
        perror("sched_setconfig_np");
        exit(EXIT_FAILURE);
    }

    printf("Successfully set SCHED_TP configuration for CPU %d\n", cpu);

    // 启动 TP 调度
    config.tp.op = sched_tp_start;
    if (sched_setconfig_np(cpu, SCHED_TP, &config, len) < 0) {
        perror("sched_setconfig_np (start)");
        exit(EXIT_FAILURE);
    }

    printf("Started SCHED_TP scheduling on CPU %d\n", cpu);

    printf("Thread running with PID: %d\n", getpid());
    for (int i = 0; i < 3; i++) {
        printf("Thread: %d\n", i);
        sleep(1);
    }
    // 停止TP调度并卸载
    config.tp.op = sched_tp_stop;
    if (sched_setconfig_np(cpu, SCHED_TP, &config, len) < 0) {
        perror("sched_setconfig_np (start)");
        exit(EXIT_FAILURE);
    }
    config.tp.op = sched_tp_uninstall;
    if (sched_setconfig_np(cpu, SCHED_TP, &config, len) < 0) {
        perror("sched_setconfig_np (start)");
        exit(EXIT_FAILURE);
    }
    pthread_exit(0);
}

int main() {
    pthread_t thread;

    // 创建线程
    if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
        perror("pthread_create");
        return EXIT_FAILURE;
    }

    // 等待线程结束
    pthread_join(thread, NULL);
    printf("Thread finished.\n");

    return EXIT_SUCCESS;
}
```
---

### sched_getscheduler()

> int sched_getscheduler (pid_t pid)

获取指定进程的调度策略。

该服务检索由 **pid** 标识的 Cobalt 进程的调度策略。

如果 **pid** 未标识现有的 Cobalt 线程/进程，则该服务回退到常规的 `sched_getscheduler()` 服务。

**参数**:
- **pid**: 目标进程/线程。

**返回值**:
- 成功时返回 **0**；
- 出错时返回错误号：
    - **ESRCH**: 找不到 **pid**；
    - **EINVAL**: **pid** 为负数；
    - **EFAULT**: **param_ex** 是无效地址。

**标签**:
- `thread-unrestricted`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <sched.h>
#include <stdlib.h>
#include <errno.h>

int main() {
    // 获取当前进程的调度策略
    int policy = sched_getscheduler(0);
    if (policy == -1) {
        perror("sched_getscheduler failed");
        exit(EXIT_FAILURE);
    }

    // 根据获取的策略打印对应的调度策略名称
    switch (policy) {
        case SCHED_OTHER:
            printf("Current policy: SCHED_OTHER\n");
            break;
        case SCHED_FIFO:
            printf("Current policy: SCHED_FIFO\n");
            break;
        case SCHED_RR:
            printf("Current policy: SCHED_RR\n");
            break;
        default:
            printf("Current policy: Unknown (%d)\n", policy);
            break;
    }

    return 0;
}
```

---

### sched_getscheduler_ex()

> int sched_getscheduler_ex (pid_t pid, int *policy_r, struct sched_param_ex *param_ex)

获取进程的扩展调度策略。

该服务是 `sched_getscheduler()` 服务的扩展版本，支持 Cobalt 特定和/或主机 Linux 环境不可用的附加调度策略。它检索由 **pid** 标识的 Cobalt 进程/线程的调度策略及相关的调度参数（例如优先级）。

**参数**:
- **pid**: 查询的进程/线程。如果为零，则假定为当前线程。
- **policy_r**: 一个指向变量的指针，用于接收 **pid** 的当前调度策略。
- **param_ex**: 一个指向结构的指针，用于接收 **pid** 的当前调度参数。

**返回值**:
- 成功时返回 **0**；
- 出错时返回错误号：
    - **ESRCH**: **pid** 不是 Cobalt 线程；
    - **EINVAL**: **pid** 为负数或 **param_ex** 为 NULL；
    - **EFAULT**: **param_ex** 是无效地址。

**标签**:
- `thread-unrestricted`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <sched.h>
#include <stdlib.h>
#include <errno.h>
#include <cobalt/sched.h>

int main() {
    struct sched_param_ex param;
    int policy;

    // 获取当前进程的调度策略和参数
    sched_getscheduler_ex(0,&policy,&param);
    if (policy == -1) {
        perror("sched_getscheduler failed");
        exit(EXIT_FAILURE);
    }

    // 根据获取的策略打印对应的调度策略名称
    switch (policy) {
        case SCHED_OTHER:
            printf("Current policy: SCHED_OTHER\n");
            break;
        case SCHED_FIFO:
            printf("Current policy: SCHED_FIFO\n");
            break;
        case SCHED_RR:
            printf("Current policy: SCHED_RR\n");
            break;
        default:
            printf("Current policy: Unknown (%d)\n", policy);
            break;
    }
    // 打印当前进程的调度优先级
    printf("Current priority: %d\n", param.sched_priority);

    return 0;
}
```

---

#### sched_setscheduler()

> int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param)

设置指定进程的调度策略和参数。

该服务将由 **pid** 标识的 Cobalt 进程的调度策略设置为 **policy**，并将其调度参数（即优先级）设置为 **param** 指向的值。

如果传递当前的 Linux 线程 ID（参见 `gettid(2)`），该服务会将当前的常规 POSIX 线程转换为 Cobalt 线程。如果 **pid** 既不是当前线程的标识符，也不是现有 Cobalt 线程的标识符，则该服务回退到常规的 `sched_setscheduler()` 服务。

**参数**:
- **pid**: 目标进程/线程；
- **policy**: 调度策略，`SCHED_FIFO`、`SCHED_RR` 或 `SCHED_OTHER` 之一；
- **param**: 调度参数地址。

**返回值**:
- 成功时返回 **0**；
- 出错时返回错误号：
    - **ESRCH**: **pid** 无效；
    - **EINVAL**: **policy** 或 **param->sched_priority** 无效；
    - **EAGAIN**: 系统堆内存不足，请增加 `CONFIG_XENO_OPT_SYS_HEAPSZ`；
    - **EFAULT**: **param** 是无效地址。

**注意**:
- 参见 `sched_setscheduler_ex()`。

**标签**:
- `thread-unrestricted`，`switch-secondary`，`switch-primary`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <sched.h>
#include <stdlib.h>
#include <errno.h>

int main() {
    // 获取当前进程的调度策略
    int policy = sched_getscheduler(0);
    if (policy == -1) {
        perror("sched_getscheduler failed");
        exit(EXIT_FAILURE);
    }
     // 获取当前进程的调度参数
    struct sched_param param;
    if (sched_getparam(0, &param) == -1) {
        perror("sched_getparam failed");
        exit(EXIT_FAILURE);
    }
    printf("Befor-Set : policy[%d] priority[%d]\n",policy, param.sched_priority);

    param.sched_priority = 15;
    if (sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
        perror("sched_getparam failed");
        exit(EXIT_FAILURE);
    }
    policy = sched_getscheduler(0);
    if (policy == -1) {
        perror("sched_getscheduler failed");
        exit(EXIT_FAILURE);
    }
     // 获取当前进程的调度参数
    if (sched_getparam(0, &param) == -1) {
        perror("sched_getparam failed");
        exit(EXIT_FAILURE);
    }
    printf("After-Set : policy[%d] priority[%d]\n",policy, param.sched_priority);

    return 0;
}
```

---

#### sched_setscheduler_ex()

> int sched_setscheduler_ex (pid_t pid, int policy, const struct sched_param_ex *param_ex)

设置进程的扩展调度策略。

该服务是 `sched_setscheduler()` 服务的扩展版本，支持 Cobalt 特定和/或主机 Linux 环境不可用的附加调度策略。它将由 **pid** 标识的 Cobalt 进程/线程的调度策略设置为 **policy** 的值，并将其调度参数（例如优先级）设置为 **param_ex** 指向的值。

如果传递当前的 Linux 线程 ID 或零（参见 `gettid(2)`），该服务可能会将当前的常规 POSIX 线程转换为 Cobalt 线程。

**参数**:
- **pid**: 目标进程/线程。如果为零，则假定为当前线程。
- **policy**: 调度策略，`SCHED_WEAK`、`SCHED_FIFO`、`SCHED_COBALT`、`SCHED_RR`、`SCHED_SPORADIC`、`SCHED_TP`、`SCHED_QUOTA` 或 `SCHED_NORMAL` 之一。
- **param_ex**: 调度参数的地址。作为一个特殊例外，负的 **sched_priority** 值被解释为 **policy** 中给定的 **SCHED_WEAK**，使用该参数的绝对值作为弱优先级级别。

当启用 `CONFIG_XENO_OPT_SCHED_WEAK` 时，`SCHED_WEAK` 在 [0..99] 范围内（包括 0 和 99）展示优先级级别。否则，对于 `SCHED_WEAK` 策略，**sched_priority** 必须为零。

**返回值**:
- 成功时返回 **0**；
- 出错时返回错误号：
    - **ESRCH**: 找不到 **pid**；
    - **EINVAL**: **pid** 为负数，**param_ex** 为 NULL，**policy** 或 **param_ex->sched_priority** 无效；
    - **EAGAIN**: 系统堆内存不足，请增加 `CONFIG_XENO_OPT_SYS_HEAPSZ`；
    - **EFAULT**: **param_ex** 是无效地址；

**注意**:
- 参见 `sched_setscheduler()`。

**标签**:
- `thread-unrestricted`，`switch-secondary`，`switch-primary`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <cobalt/sched.h>

int main() {
    struct sched_param param;
    int policy;
    // 获取当前进程的调度策略和参数
    sched_getscheduler_ex(0,&policy,&param);
    if (policy == -1) {
        perror("sched_getscheduler failed");
        exit(EXIT_FAILURE);
    }
    printf("Befor-Set : policy[%d] priority[%d]\n",policy, param.sched_priority);

    param.sched_priority = 15;
    if (sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
        perror("sched_getparam failed");
        exit(EXIT_FAILURE);
    }

    sched_getscheduler_ex(0,&policy,&param);
    if (policy == -1) {
        perror("sched_getscheduler failed");
        exit(EXIT_FAILURE);
    }
    printf("After-Set : policy[%d] priority[%d]\n",policy, param.sched_priority);

    return 0;
}
```

---

#### sched_yield()

> int sched_yield (void)

让出处理器。

此函数将当前线程移动到其优先级组的末尾。

**返回值**:
- **0**

**标签**:
- `thread-unrestricted`，`switch-primary`

引用 `XNRELAX` 和 `XNWEAK`。

被 `pthread_yield()` 引用。

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sched.h>
#include <unistd.h>

#define NUM_THREADS 3

void* thread_function(void* arg) {
    int thread_id = *((int*)arg);
    for (int i = 0; i < 5; ++i) {
        printf("Thread %d: working...\n", thread_id);
        // 模拟工作
        usleep(100000); // 睡眠 100 毫秒
        
        // 调用 sched_yield() 放弃 CPU
        printf("Thread %d: yielding...\n", thread_id);
        sched_yield();
    }
    return NULL;
}

int main() {
    pthread_t threads[NUM_THREADS];
    int thread_ids[NUM_THREADS];

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; ++i) {
        thread_ids[i] = i + 1;
        if (pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]) != 0) {
            perror("Failed to create thread");
            exit(EXIT_FAILURE);
        }
    }

    // 等待所有线程完成
    for (int i = 0; i < NUM_THREADS; ++i) {
        pthread_join(threads[i], NULL);
    }

    printf("All threads have finished.\n");
    return 0;
}
```

---