### 详细描述

Cobalt（POSIX）线程管理服务。

---
### 函数文档

#### pthread_create()

> int pthread_create(pthread_t *ptid_r, const pthread_attr_t *attr, void *(*start)(void *), void *arg)

创建新线程。

此服务在双内核配置中创建由 Cobalt 核心管理的线程。

新线程的属性取决于 `attr` 参数。如果 `attr` 为 NULL，则使用这些属性的默认值。

从 `start` 例程返回的效果与调用 `pthread_exit()` 并传递返回值相同。

**参数**:
- **ptid_r**: 成功时存储新线程标识符的地址；
- **attr**: 线程属性；
- **start**: 线程启动例程；
- **arg**: 传递给 `start` 的用户提供的不透明参数。

**返回值**:
- 成功时返回 **0**；
- 出错时返回错误号：
    - **EINVAL**: `attr` 无效；
    - **EAGAIN**: 系统堆内存不足，无法创建新线程，请增加 `CONFIG_XENO_OPT_SYS_HEAPSZ`；
    - **EINVAL**: 线程属性 `inheritsched` 设置为 `PTHREAD_INHERIT_SCHED`，且调用线程不属于 Cobalt 接口。

**注意**:
首次创建 Cobalt 线程时，libcobalt 会为 `SIGSHADOW` 信号安装一个内部处理程序。如果您之前为该信号安装了处理程序，则该处理程序将仅在 xkernel 未发送 `SIGSHADOW` 时被调用。

但是，如果之后安装了应用程序定义的 `SIGSHADOW` 处理程序，覆盖了 libcobalt 处理程序，则新处理程序需要在进入时调用 `cobalt_sigshadow_handler()`。此例程对于每次由 Cobalt 核心发出的 `SIGSHADOW` 返回非零值。如果返回零，则应用程序定义的处理程序应处理该信号。

```c
int cobalt_sigshadow_handler(int sig, siginfo_t *si, void *ctxt);
```

您应使用 `sigaction(2)` 注册处理程序，并设置 `SA_SIGINFO` 标志。

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

示例代码

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

// 线程要执行的函数
void* thread_function(void* arg) {
    int thread_id = *((int*)arg);
    printf("Thread%d is running\n", thread_id);
    sleep(1);  // 模拟一些工作
    printf("Thread%d finished\n", thread_id);
    return NULL;
}

int main() {
    pthread_t threads[5]; // 创建5个线程
    int thread_ids[5];    // 用于存储线程ID

    for (int i = 0; i < 5; i++) {
        thread_ids[i] = i; // 设置线程ID
        // 创建线程
        if (pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]) != 0) {
            perror("pthread_create");
            return 1;
        }
    }

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

    printf("Thread Work Finished\n");
    return 0;
}
```

---

#### pthread_join()

> int pthread_join(pthread_t thread, void **ret_val)

等待指定线程终止。

如果 `thread` 正在运行且可连接，此服务将阻塞调用者，直到 `thread` 终止或分离。当 `thread` 终止时，调用者将被解除阻塞，并将其返回值存储在 `ret_val` 指向的地址中。

另一方面，如果 `thread` 已经完成执行，其先前收集的返回值将存储在 `ret_val` 指向的地址中，并且此服务将立即返回。

对于 Cobalt 线程，此服务是一个取消点：如果调用线程在调用此服务时被取消，则取消请求将被接受，并且 `thread` 仍然是可连接的。

多个同时调用 `pthread_join()` 指定相同运行目标线程的调用者将全部阻塞，直到目标线程终止。

**参数**:
- **thread**: 要等待的线程标识符；
- **ret_val**: 成功时存储目标线程返回值的地址。

**返回值**:
- 成功时返回 **0**；
- 出错时返回错误号：
    - **ESRCH**: `thread` 无效；
    - **EDEADLK**: 尝试连接调用线程自身；
    - **EINVAL**: `thread` 已分离；
    - **EPERM**: 调用者上下文无效。

**标签**:
- `xthread-only`，`switch-secondary`，`switch-primary`

示例代码

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

// 线程要执行的函数
void* thread_function(void* arg) {
    int thread_id = *((int*)arg);
    printf("Thread%d is running\n", thread_id);
    sleep(1);  // 模拟一些工作
    printf("Thread%d finished\n", thread_id);
    return NULL;
}

int main() {
    pthread_t threads[5]; // 创建5个线程
    int thread_ids[5];    // 用于存储线程ID

    for (int i = 0; i < 5; i++) {
        thread_ids[i] = i; // 设置线程ID
        // 创建线程
        if (pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]) != 0) {
            perror("pthread_create");
            return 1;
        }
    }

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

    printf("Thread Work Finished\n");
    return 0;
}
```

---

#### pthread_kill()

> int pthread_kill(pthread_t thread, int sig)

向线程发送信号。

此服务向 Cobalt 线程 `thread`（通过 `pthread_create()` 创建）发送信号 `sig`。如果 `sig` 为零，此服务将检查线程 `thread` 的存在性，但不会发送任何信号。

**参数**:
- **thread**: 线程标识符；
- **sig**: 信号编号。

**返回值**:
- 成功时返回 **0**；
- 出错时返回错误号：
    - **EINVAL**: `sig` 是无效的信号编号；
    - **EAGAIN**: 超过了最大挂起信号数；
    - **ESRCH**: `thread` 是无效的线程标识符。

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

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <cobalt/wrappers.h>
pthread_t thread1,thread2;

void *thread_function1(void *arg) {
    // 初始化信号集
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGQUIT);
    int sig;
    
    printf("Thread1 started, waiting for signal...\n");
    // 阻塞并等待信号
    if(sigwait(&set,&sig) == 0)
    {
        printf("thread1 get SIGQUIT signal\n");
    }else{
        perror("sigwait");
    } 
    printf("Thread1 finished.\n");
    return NULL;
}
void *thread_function2(void *arg) {
    // 初始化信号集
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGUSR1);
    int sig;

    printf("Thread2 started, waiting for signal...\n");
    // 阻塞并等待信号
    if(sigwait(&set,&sig) == 0)
    {
        printf("thread2 get SIGUSR1 signal\n");
    }else{
        perror("sigwait");
    }
    printf("Thread2 finished.\n");
    return NULL;
}

int main() {
    // 创建线程
    if (pthread_create(&thread1, NULL, thread_function1, NULL) != 0) {
        perror("Failed to create thread");
        return 1;
    }
    if (pthread_create(&thread2, NULL, thread_function2, NULL) != 0) {
        perror("Failed to create thread");
        return 1;
    }

    sleep(1);
    // 发送信号给Thread1
    pthread_kill(thread1, SIGQUIT);
    // 发送信号给Thread2
    pthread_kill(thread2, SIGUSR1);
    // 等待线程结束
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    return 0;
}

```

---

#### pthread_setmode_np()

> int pthread_setmode_np(int clrmask, int setmask, int *mode_r)

设置当前线程的模式。

此服务设置调用线程的模式，影响其在特定情况下的行为。`clrmask` 和 `setmask` 是两个模式位掩码，分别由 `pthread_setmode_np()` 清除和设置。

- **PTHREAD_LOCK_SCHED**: 设置时，锁定调度器，防止当前线程被切换出去，直到调度器被解锁。除非同时设置了 `PTHREAD_DISABLE_LOCKBREAK`，线程仍可能阻塞，暂时释放锁，在这种情况下，当线程恢复执行时，锁将自动重新获取。
- **PTHREAD_WARNSW**: 设置时，为当前线程启用调试通知。当检测到以下典型或异常行为时，会发送 `SIGDEBUG` 信号（源自 Linux）。
- **PTHREAD_DISABLE_LOCKBREAK**: 禁止打破调度器锁。通常，当当前所有者阻塞时，调度器锁会隐式释放，然后在恢复执行时自动重新获取。
- **PTHREAD_CONFORMING**: 可以在 `setmask` 中传递，以将当前 Cobalt 线程切换到其首选的运行模式。

此服务是 Cobalt 接口的非可移植扩展。

**参数**:
- **clrmask**: 要清除的位集合。
- **setmask**: 要设置的位集合。
- **mode_r**: 如果非 NULL，`mode_r` 必须是一个指向内存位置的指针，成功时将写入先前的活动模式位集合。

**返回值**:
- 成功时返回 **0**，否则：
    - **EINVAL**: `clrmask` 或 `setmask` 中的某些位无效。

**注意**:
- 将 `clrmask` 和 `setmask` 设置为零会导致无操作，仅在 `mode_r` 是有效地址时返回先前的模式。

**注意**:
- 在常规应用中使用 `PTHREAD_CONFORMING` 很可能是无用的，甚至会引入纯粹的开销。

**标签**:
- `xthread-only`，`switch-primary`

示例代码

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

void* thread_function(void* arg) {
    int thread_id = *(int*)arg;
    printf("Thread %d is running...\n", thread_id);
    sleep(2);
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    int thread_id1 = 1, thread_id2 = 2;
    
    // 创建第一个线程
    if (pthread_create(&thread1, NULL, thread_function, &thread_id1) != 0) {
        perror("Failed to create thread 1");
        return 1;
    }
    
    // 创建第二个线程
    if (pthread_create(&thread2, NULL, thread_function, &thread_id2) != 0) {
        perror("Failed to create thread 2");
        return 1;
    }
    int mode = 0;
    // 设置当前线程的模式
    if (pthread_setmode_np(PTHREAD_WARNSW|PTHREAD_LOCK_SCHED, 0, &mode) != 0) {
        perror("pthread_setmode_np");
        return 1;
    }

    // 等待线程结束
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    
    // 取消线程模式
    if (pthread_setmode_np(0, PTHREAD_WARNSW|PTHREAD_LOCK_SCHED, &mode) != 0) {
        perror("pthread_setmode_np");
        return 1;
    }

    printf("Both threads have finished execution.\n");
    
    return 0;
}

```

---

#### pthread_setname_np()

> int pthread_setname_np(pthread_t thread, const char *name)

设置线程名称。

此服务将线程 `thread` 的名称设置为 `name`。该名称用于在 `/proc/xenomai/sched` 中显示信息。

此服务是 Cobalt 接口的非可移植扩展。

**参数**:
- **thread**: 目标线程。
- **name**: 线程名称。

**返回值**:
- 成功时返回 **0**，否则：
    - **ESRCH**: `thread` 无效。

**标签**:
- `xthread-only`

示例代码

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

void* thread_function(void* arg) {
    printf("Thread %ld is running...\n", (long)arg);
    sleep(10);
    return NULL;
}

int main() {
    pthread_t thread;
    const char* thread_name = "Sinsegye";

    // 创建线程
    if (pthread_create(&thread, NULL, thread_function, (void*)1) != 0) {
        perror("Failed to create thread");
        return 1;
    }

    // 设置线程名称
    if (pthread_setname_np(thread, thread_name) != 0) {
        perror("Failed to set thread name");
        return 1;
    }

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

    return 0;
}
```

---