### 详细描述

Cobalt/POSIX 信号量服务。

信号量是在线程之间共享资源的计数器。信号量的基本操作是：原子性地增加计数器，以及等待计数器为非零并原子性地减少它。

信号量有一个最大值，超过该值后不能再增加。宏 **SEM_VALUE_MAX** 被定义为此最大值。

---
### 函数文档

### sem_close()

> int sem_close (sem_t *sem)

关闭命名信号量。

此服务关闭信号量 **sem**。信号量仅在调用 `sem_unlink()` 服务取消链接并且每次调用 `sem_open()` 都匹配一次此服务调用时才会被销毁。

当信号量被销毁时，它使用的内存将返回到系统堆，因此进一步引用此信号量不保证失败，这与未命名信号量的情况相同。

如果 **sem** 是未命名信号量，则此服务将失败。

**参数**:
- **sem**: 要关闭的信号量。

**返回值**:
- 成功时返回 **0**；
- 出错时返回 **-1** 并设置 `errno`：
    - **EINVAL**，信号量 **sem** 无效或是未命名信号量。

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

示例代码

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

#define NUM_THREADS 5
#define SEM_NAME "/my_semaphore"

sem_t *sem;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    sem_wait(sem);
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(sem);
    
    return NULL;
}

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

    // 创建信号量，初始值为1
    sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

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

    // 关闭信号量
    if (sem_close(sem) == -1) {
        perror("sem_close failed");
    }
    
    // 删除信号量
    if (sem_unlink(SEM_NAME) == -1) {
        perror("sem_unlink failed");
    }

    return 0;
}

```

---

#### sem_destroy()

> int sem_destroy (sem_t *sem)

销毁未命名信号量。

此服务销毁信号量 **sem**。当前阻塞在 **sem** 上的线程将被解除阻塞，并且它们调用的服务将返回 **-1**，并将 `errno` 设置为 **EINVAL**。然后，信号量被所有信号量服务视为无效（它们都将失败并将 `errno` 设置为 **EINVAL**），除了 `sem_init()`。

如果 **sem** 是命名信号量，则此服务将失败。

**参数**:
- **sem**: 要销毁的信号量。

**返回值**:
- 成功时总是返回 **0**。
    - 如果在 `sem_init_np()` 中提到了 **SEM_WARNDEL**，则信号量按请求删除，并返回一个严格的正值以警告调用者是否有线程在等待，否则返回零。
    - 如果在 `sem_init_np()` 中提到了 **SEM_NOBUSYDEL**，则 `sem_destroy()` 仅在没有线程等待信号量删除时才可能成功；否则返回 **-EBUSY**。

- 如果出错，返回 **-1** 并设置 `errno`：
    - **EINVAL**: 信号量 **sem** 无效或是命名信号量；
    - **EPERM**: 信号量 **sem** 是进程共享的，并且不属于当前进程；
    - **EBUSY**: 当前有线程在信号量 **sem** 上等待，并且设置了 **SEM_NOBUSYDEL**。

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

示例代码

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

#define NUM_THREADS 5

sem_t semaphore;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    sem_wait(&semaphore);
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(&semaphore);
    
    return NULL;
}

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

    // 初始化信号量，初始值为2（表示可以有两个线程进入临界区）
    if (sem_init(&semaphore, 0, 2) != 0) {
        perror("sem_init failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

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

    // 销毁信号量
    if (sem_destroy(&semaphore) != 0) {
        perror("sem_destroy failed");
    }

    return 0;
}
```

---

#### sem_init()

> int sem_init (sem_t *sem, int pshared, unsigned int value)

初始化未命名信号量。

此服务初始化信号量 **sem**，初始值为 **value**。

如果 **sem** 已经初始化或是命名信号量，则此服务将失败。

**参数**:
- **sem**: 要初始化的信号量。
- **pshared**: 如果为零，表示新信号量只能被调用 `sem_init()` 的线程所在的同一进程中的线程使用；如果为非零，表示新信号量可以被任何有权访问信号量所在内存的线程使用。
- **value**: 信号量的初始值。

**返回值**:
- 成功时返回 **0**；
- 出错时返回 **-1** 并设置 `errno`：
    - **EBUSY**: 信号量 **sem** 已经初始化；
    - **EAGAIN**: 初始化信号量的内存不足，对于进程共享信号量，请增加 `CONFIG_XENO_OPT_SHARED_HEAPSZ`，对于进程私有信号量，请增加 `CONFIG_XENO_OPT_PRIVATE_HEAPSZ`；
    - **EAGAIN**: 没有可用的注册槽，请检查/增加 `CONFIG_XENO_OPT_REGISTRY_NRSLOTS`；
    - **EINVAL**: 参数 **value** 超过 `SEM_VALUE_MAX`。

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

示例代码

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

#define NUM_THREADS 5

sem_t semaphore;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    sem_wait(&semaphore);
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(&semaphore);
    
    return NULL;
}

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

    // 初始化信号量，初始值为2（表示可以有两个线程进入临界区）
    if (sem_init(&semaphore, 0, 2) != 0) {
        perror("sem_init failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

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

    // 销毁信号量
    if (sem_destroy(&semaphore) != 0) {
        perror("sem_destroy failed");
    }

    return 0;
}

```

---

#### sem_post()

> int sem_post (sem_t *sem)

释放信号量。

此服务释放信号量 **sem**。

如果当前没有线程阻塞在此信号量上，并且未启用“脉冲”模式（参见 `sem_init_np()`，`SEM_PULSE`），则其计数将增加。如果有线程阻塞在信号量上，则等待队列中的第一个线程将被解除阻塞。

**参数**:
- **sem**: 要释放的信号量。

**返回值**:
- 成功时返回 **0**；
- 出错时返回 **-1** 并设置 `errno`：
    - **EINVAL**: 指定的信号量无效或未初始化；
    - **EPERM**: 信号量 **sem** 不是进程共享的，并且不属于当前进程；
    - **EAGAIN**: 信号量计数已达到 `SEM_VALUE_MAX`。

**标签**:
- `unrestricted`

示例代码

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

#define NUM_THREADS 5
#define SEM_NAME "/my_semaphore"

sem_t *sem;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    sem_wait(sem);
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(sem);
    
    return NULL;
}

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

    // 创建信号量，初始值为1
    sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

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

    // 关闭信号量
    if (sem_close(sem) == -1) {
        perror("sem_close failed");
    }
    
    // 删除信号量
    if (sem_unlink(SEM_NAME) == -1) {
        perror("sem_unlink failed");
    }

    return 0;
}

```

---

#### sem_trywait()

> int sem_trywait (sem_t *sem)

尝试减少信号量。

此服务等同于 `sem_wait()`，但如果信号量 **sem** 当前已耗尽，它会立即返回，并且它不是一个取消点。

**参数**:
- **sem**: 要减少的信号量。

**返回值**:
- 成功时返回 **0**；
- 出错时返回 **-1** 并设置 `errno`：
    - **EINVAL**: 指定的信号量无效或未初始化；
    - **EPERM**: 信号量 **sem** 不是进程共享的，并且不属于当前进程；
    - **EAGAIN**: 指定的信号量当前已完全耗尽。

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

示例代码

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

#define NUM_THREADS 5
#define SEM_NAME "/my_semaphore"

sem_t *sem;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    while(sem_trywait(sem) != 0) {
        sleep(1);
    }
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(sem);
    
    return NULL;
}

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

    // 创建信号量，初始值为1
    sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

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

    // 关闭信号量
    if (sem_close(sem) == -1) {
        perror("sem_close failed");
    }
    
    // 删除信号量
    if (sem_unlink(SEM_NAME) == -1) {
        perror("sem_unlink failed");
    }

    return 0;
}

```

---

#### sem_unlink()

> int sem_unlink (const char *name)

取消命名信号量的链接。

此服务取消名为 **name** 的信号量的链接。该信号量在通过调用 `sem_close()` 关闭所有通过 `sem_open()` 获取的引用之前不会被销毁。然而，取消链接的信号量将无法再通过 `sem_open()` 服务访问。

当信号量被销毁时，它使用的内存将返回到系统堆，因此进一步引用此信号量不保证失败，这与未命名信号量的情况相同。

**参数**:
- **name**: 要取消链接的信号量的名称。

**返回值**:
- 成功时返回 **0**；
- 出错时返回 **-1** 并设置 `errno`：
    - **ENAMETOOLONG**: **name** 参数的长度超过 64 个字符；
    - **ENOENT**: 指定名称的信号量不存在。

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

示例代码

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

#define NUM_THREADS 5
#define SEM_NAME "/my_semaphore"

sem_t *sem;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    sem_wait(sem);
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(sem);
    
    return NULL;
}

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

    // 创建信号量，初始值为1
    sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

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

    // 关闭信号量
    if (sem_close(sem) == -1) {
        perror("sem_close failed");
    }
    
    // 删除信号量
    if (sem_unlink(SEM_NAME) == -1) {
        perror("sem_unlink failed");
    }

    return 0;
}

```

---

#### sem_wait()

> int sem_wait(sem_t *sem)

减少信号量。

此服务在信号量 **sem** 的当前值大于 0 时减少其值。如果信号量的当前值为零，则调用线程将被挂起，直到信号量被释放，或者一个信号被传递给调用线程。

对于通过 `pthread_create()` 服务创建的 Cobalt 线程，此服务是一个取消点。当这样的线程在调用此服务时被取消时，在调用取消清理处理程序之前，信号量状态保持不变。

**参数**:
- **sem**: 要减少的信号量。

**返回值**:
- 成功时返回 **0**；
- 出错时返回 **-1** 并设置 `errno`：
    - **EPERM**: 调用者上下文无效；
    - **EINVAL**: 信号量无效或未初始化；
    - **EPERM**: 信号量 **sem** 不是进程共享的，并且不属于当前进程；
    - **EINTR**: 调用者在此服务中被信号中断。

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

示例代码

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

#define NUM_THREADS 5
#define SEM_NAME "/my_semaphore"

sem_t *sem;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    sem_wait(sem);
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(sem);
    
    return NULL;
}

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

    // 创建信号量，初始值为1
    sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

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

    // 关闭信号量
    if (sem_close(sem) == -1) {
        perror("sem_close failed");
    }
    
    // 删除信号量
    if (sem_unlink(SEM_NAME) == -1) {
        perror("sem_unlink failed");
    }

    return 0;
}

```

---