### 详细描述

计数信号量 IPC 机制。

计数信号量是一种同步对象，用于控制多个实时任务访问资源时允许的并发级别，基于原子访问的计数变量的值。信号量通过 P（“Proberen”，荷兰语中的“测试和递减”）和 V（“Verhogen”，递增）操作来使用。P 操作在计数非零时将信号量计数减一，或者等待直到另一个任务发出 V 操作。相反，V 操作通过将计数加一来释放资源，如果有任务在等待 P 操作，则解除其阻塞。等待信号量可能导致优先级反转。

如果在任何时候最多只有一个资源可用，信号量将强制互斥，因此可以用于串行化对临界区的访问。然而，应使用互斥锁来防止基于优先级继承协议的优先级反转。

---
### 函数文档

#### rt_sem_bind

> int rt_sem_bind (RT_SEM *sem, const char *name, RTIME timeout);

绑定到信号量。

此例程创建一个新的描述符，以引用由其符号名称标识的现有信号量。如果在进入时对象不存在，调用者可能会阻塞，直到创建具有给定名称的信号量。

**参数**

- **sem**: 操作填充的信号量描述符的地址。失败时此内存的内容未定义。
- **name**: 一个有效的以 NULL 结尾的名称，用于标识要绑定的信号量。此字符串应与传递给 rt_sem_create() 的对象名称参数匹配。
- **timeout**: 等待注册发生的时钟滴答数（见注释）。传递 TM_INFINITE 会导致调用者无限期阻塞，直到对象注册。传递 TM_NONBLOCK 会导致服务立即返回而不等待，如果在进入时对象未注册。

**返回值**

成功时返回零。否则：
- 如果在检索完成之前为当前任务调用了 rt_task_unblock()，则返回 **-EINTR**。
- 如果 timeout 等于 TM_NONBLOCK 且在进入时未注册所搜索的对象，则返回 **-EWOULDBLOCK**。
- 如果在指定时间内无法检索到对象，则返回 **-ETIMEDOUT**。
- 如果此服务应阻塞，但不是从 xkernel 线程调用的，则返回 **-EPERM**。

**标签**

`xthread-nowait`, `switch-primary`

**注释**

超时值被解释为 Alchemy 时钟分辨率的倍数（见 --alchemy-clock-resolution 选项，默认为 1 纳秒）。

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <alchemy/task.h>
#include <alchemy/sem.h>
#include <alchemy/timer.h>

#define TASK_PRIO 50
#define TASK_MODE T_JOINABLE
#define TASK_STKSZ 0

RT_TASK producer_task, consumer_task;
RT_SEM sem;
int data = 0;

void producer(void *arg)
{
    RT_SEM sem_producer;
    
    int ret = rt_sem_bind(&sem_producer, "MySemaphore", TM_INFINITE);
    if (ret < 0) {
        printf("Error bind semaphore: %d\n", ret);
        return;
    }

    while (data < 3) {
        printf("Producer: Producing item\n");
        rt_task_sleep(1000000000);  // 睡眠 1 秒
        data++;
        rt_sem_v(&sem_producer);
        printf("Producer: Item produced\n");
    }

    ret = rt_sem_unbind(&sem_producer);
    if (ret < 0) {
        printf("Error unbind semaphore: %d\n", ret);
        return;
    }
}

void consumer(void *arg)
{
     RT_SEM sem_consumer;
    
    int ret = rt_sem_bind(&sem_consumer, "MySemaphore", TM_INFINITE);
    if (ret < 0) {
        printf("Error bind semaphore: %d\n", ret);
        return;
    }

    while (data < 3) {
        printf("Consumer: Waiting for item\n");
        rt_sem_p(&sem_consumer, TM_INFINITE);
        printf("Consumer: Item consumed, data = %d\n\n",data);
    }

    ret = rt_sem_unbind(&sem_consumer);
    if (ret < 0) {
        printf("Error unbind semaphore: %d\n", ret);
        return;
    }
}

int main(int argc, char *argv[])
{
    int ret;

    // 创建信号量
    ret = rt_sem_create(&sem, "MySemaphore", 0, S_FIFO);
    if (ret < 0) {
        printf("Error creating semaphore: %d\n", ret);
        return EXIT_FAILURE;
    }

    //  创建生产者任务
    ret = rt_task_create(&producer_task, "Producer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating producer task: %d\n", ret);
        goto cleanup_sem;
    }

    // 创建消费者任务
    ret = rt_task_create(&consumer_task, "Consumer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating consumer task: %d\n", ret);
        goto cleanup_producer;
    }

    // 启动任务
    rt_task_start(&producer_task, &producer, NULL);
    rt_task_start(&consumer_task, &consumer, NULL);

    // 等待任务完成
    rt_task_join(&producer_task);
    rt_task_join(&consumer_task);

    // 清理
    rt_task_delete(&consumer_task);
cleanup_producer:
    rt_task_delete(&producer_task);
cleanup_sem:
    rt_sem_delete(&sem);

    return EXIT_SUCCESS;
}
```

---

#### rt_sem_broadcast

> int rt_sem_broadcast (RT_SEM *sem);

广播信号量。

所有当前等待信号量的任务将立即解除阻塞。信号量计数被设置为零。

**参数**

- **sem**: 信号量描述符。

**返回值**

成功时返回零。否则：
- 如果 sem 不是有效的信号量描述符，则返回 **-EINVAL**。

**标签**

`unrestricted`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <alchemy/task.h>
#include <alchemy/sem.h>
#include <alchemy/timer.h>

#define TASK_PRIO 50
#define TASK_MODE T_JOINABLE
#define TASK_STKSZ 0

RT_TASK producer_task, consumer_task1, consumer_task2;
RT_SEM sem;
int data = 0;

void producer(void *arg)
{
    while (data < 3) {
        printf("Producer: Producing item\n");
        rt_task_sleep(1000000000);  // 睡眠 1 秒
        data++;
        rt_sem_broadcast(&sem);
        printf("Producer: Item produced\n\n");
    }
}

void consumer(void *arg)
{
    int task_id = (int)(long)arg;

    while (data < 3) {
        printf("Consumer %d: Waiting for item\n",task_id);
        rt_sem_p(&sem, TM_INFINITE);
        printf("Consumer %d: Item consumed, data = %d\n",task_id,data);
    }
}

int main(int argc, char *argv[])
{
    int ret;

    // 创建信号量
    ret = rt_sem_create(&sem, "MySemaphore", 0, S_FIFO);
    if (ret < 0) {
        printf("Error creating semaphore: %d\n", ret);
        return EXIT_FAILURE;
    }

    //  创建生产者任务
    ret = rt_task_create(&producer_task, "Producer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating producer task: %d\n", ret);
        goto cleanup_sem;
    }

    // 创建消费者任务1
    ret = rt_task_create(&consumer_task1, "Consumer1", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating consumer task: %d\n", ret);
        goto cleanup_producer;
    }

    // 创建消费者任务2
    ret = rt_task_create(&consumer_task2, "Consumer2", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating consumer task: %d\n", ret);
        goto cleanup_consumer;
    }

    // 启动任务
    rt_task_start(&producer_task, &producer, NULL);
    rt_task_start(&consumer_task1, &consumer, (void *)1);
    rt_task_start(&consumer_task2, &consumer, (void *)2);

    // 等待任务完成
    rt_task_join(&producer_task);
    rt_task_join(&consumer_task1);
    rt_task_join(&consumer_task2);

    // 清理
    rt_task_delete(&consumer_task2);
cleanup_consumer:
    rt_task_delete(&consumer_task1);
cleanup_producer:
    rt_task_delete(&producer_task);
cleanup_sem:
    rt_sem_delete(&sem);

    return EXIT_SUCCESS;
}
```

---

#### rt_sem_create

> int rt_sem_create (RT_SEM *sem, const char *name, unsigned long icount, int mode);

创建计数信号量。

**参数**

- **sem**: 信号量描述符的地址，成功创建后可用于唯一标识该对象。
- **name**: 表示信号量符号名称的 ASCII 字符串。当非 NULL 且非空时，此字符串的副本将用于将创建的信号量索引到对象注册表中。
- **icount**: 计数信号量的初始值。
- **mode**: 信号量创建模式。以下标志可以 OR 进此位掩码：
    - **S_FIFO** 使任务以 FIFO 顺序等待信号量。
    - **S_PRIO** 使任务以优先级顺序等待信号量。
    - **S_PULSE** 使信号量以“脉冲”模式运行。在此模式下，V（信号）操作每次调用时尝试释放一个等待者，而不增加信号量计数，即使没有等待者在等待。因此，在脉冲模式下，信号量计数保持为零。

**返回值**

成功时返回零。否则：
- 如果 icount 非零且 mode 中设置了 S_PULSE，或 mode 无效，则返回 **-EINVAL**。
- 如果系统无法从主堆中获取内存以创建信号量，则返回 **-ENOMEM**。
- 如果名称与已注册的信号量冲突，则返回 **-EEXIST**。
- 如果此服务从无效上下文（例如中断或非 xkernel 线程）调用，则返回 **-EPERM**。

**标签**

`xthread-only`, `mode-unrestricted`, `switch-secondary`

**注意**

信号量可以由属于同一 xkernel 会话的多个进程共享。

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <alchemy/task.h>
#include <alchemy/sem.h>
#include <alchemy/timer.h>

#define TASK_PRIO 50
#define TASK_MODE T_JOINABLE
#define TASK_STKSZ 0

RT_TASK producer_task, consumer_task;
RT_SEM sem;
int data = 0;

void producer(void *arg)
{
    while (data < 3) {
        printf("Producer: Producing item\n");
        rt_task_sleep(1000000000);  // 睡眠 1 秒
        data++;
        rt_sem_v(&sem);
        printf("Producer: Item produced\n");
    }
}

void consumer(void *arg)
{
    while (data < 3) {
        printf("Consumer: Waiting for item\n");
        rt_sem_p(&sem, TM_INFINITE);
        printf("Consumer: Item consumed, data = %d\n\n",data);
    }
}

int main(int argc, char *argv[])
{
    int ret;

    // 创建信号量
    ret = rt_sem_create(&sem, "MySemaphore", 0, S_FIFO);
    if (ret < 0) {
        printf("Error creating semaphore: %d\n", ret);
        return EXIT_FAILURE;
    }

    //  创建生产者任务
    ret = rt_task_create(&producer_task, "Producer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating producer task: %d\n", ret);
        goto cleanup_sem;
    }

    // 创建消费者任务
    ret = rt_task_create(&consumer_task, "Consumer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating consumer task: %d\n", ret);
        goto cleanup_producer;
    }

    // 启动任务
    rt_task_start(&producer_task, &producer, NULL);
    rt_task_start(&consumer_task, &consumer, NULL);

    // 等待任务完成
    rt_task_join(&producer_task);
    rt_task_join(&consumer_task);

    // 清理
    rt_task_delete(&consumer_task);
cleanup_producer:
    rt_task_delete(&producer_task);
cleanup_sem:
    rt_sem_delete(&sem);

    return EXIT_SUCCESS;
}
```

---

#### rt_sem_delete

> int rt_sem_delete (RT_SEM *sem);

删除信号量。

此例程删除之前通过调用 rt_sem_create() 创建的信号量。

**参数**

- **sem**: 信号量描述符。

**返回值**

成功时返回零。否则：
- 如果 sem 不是有效的信号量描述符，则返回 **-EINVAL**。
- 如果此服务从异步上下文调用，则返回 **-EPERM**。

**标签**

`mode-unrestricted`, `switch-secondary`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <alchemy/task.h>
#include <alchemy/sem.h>
#include <alchemy/timer.h>

#define TASK_PRIO 50
#define TASK_MODE T_JOINABLE
#define TASK_STKSZ 0

RT_TASK producer_task, consumer_task;
RT_SEM sem;
int data = 0;

void producer(void *arg)
{
    while (data < 3) {
        printf("Producer: Producing item\n");
        rt_task_sleep(1000000000);  // 睡眠 1 秒
        data++;
        rt_sem_v(&sem);
        printf("Producer: Item produced\n");
    }
}

void consumer(void *arg)
{
    while (data < 3) {
        printf("Consumer: Waiting for item\n");
        rt_sem_p(&sem, TM_INFINITE);
        printf("Consumer: Item consumed, data = %d\n\n",data);
    }
}

int main(int argc, char *argv[])
{
    int ret;

    // 创建信号量
    ret = rt_sem_create(&sem, "MySemaphore", 0, S_FIFO);
    if (ret < 0) {
        printf("Error creating semaphore: %d\n", ret);
        return EXIT_FAILURE;
    }

    //  创建生产者任务
    ret = rt_task_create(&producer_task, "Producer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating producer task: %d\n", ret);
        goto cleanup_sem;
    }

    // 创建消费者任务
    ret = rt_task_create(&consumer_task, "Consumer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating consumer task: %d\n", ret);
        goto cleanup_producer;
    }

    // 启动任务
    rt_task_start(&producer_task, &producer, NULL);
    rt_task_start(&consumer_task, &consumer, NULL);

    // 等待任务完成
    rt_task_join(&producer_task);
    rt_task_join(&consumer_task);

    // 清理
    rt_task_delete(&consumer_task);
cleanup_producer:
    rt_task_delete(&producer_task);
cleanup_sem:
    rt_sem_delete(&sem);

    return EXIT_SUCCESS;
}
```

---

#### rt_sem_inquire

> int rt_sem_inquire (RT_SEM *sem, RT_SEM_INFO *info);

查询信号量状态。

此例程返回指定信号量的状态信息。

**参数**

- **sem**: 信号量描述符。
- **info**: 一个指向返回缓冲区的指针，用于复制信息。

**返回值**

成功时返回零，并将状态信息写入 info 指向的结构体。否则：
- 如果 sem 不是有效的信号量描述符，则返回 **-EINVAL**。

**标签**

`unrestricted`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <alchemy/task.h>
#include <alchemy/sem.h>
#include <alchemy/timer.h>

#define TASK_PRIO 50
#define TASK_MODE T_JOINABLE
#define TASK_STKSZ 0

RT_TASK producer_task, consumer_task;
RT_SEM sem;
int data = 0;

void producer(void *arg)
{
    int ret = 0;
    RT_SEM_INFO info;

    while (data < 3) {
        printf("Producer: Producing item\n");
        rt_task_sleep(1000000000);  // 睡眠 1 秒
        data++;
        rt_sem_v(&sem);

        ret = rt_sem_inquire(&sem, &info);
        if (ret < 0) {
            printf("Error creating semaphore: %d\n", ret);
            return;
        }
        printf("Producer: Get info:\n");
        printf("    name:%s, nwaiters:%d, sem_value:%ld\n",info.name,info.nwaiters,info.count);
        printf("Producer: Item produced\n");
    }
}

void consumer(void *arg)
{
    while (data < 3) {
        printf("Consumer: Waiting for item\n");
        rt_sem_p(&sem, TM_INFINITE);
        printf("Consumer: Item consumed, data = %d\n\n",data);
    }
}

int main(int argc, char *argv[])
{
    int ret;

    // 创建信号量
    ret = rt_sem_create(&sem, "MySemaphore", 0, S_FIFO);
    if (ret < 0) {
        printf("Error creating semaphore: %d\n", ret);
        return EXIT_FAILURE;
    }

    //  创建生产者任务
    ret = rt_task_create(&producer_task, "Producer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating producer task: %d\n", ret);
        goto cleanup_sem;
    }

    // 创建消费者任务
    ret = rt_task_create(&consumer_task, "Consumer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating consumer task: %d\n", ret);
        goto cleanup_producer;
    }

    // 启动任务
    rt_task_start(&producer_task, &producer, NULL);
    rt_task_start(&consumer_task, &consumer, NULL);

    // 等待任务完成
    rt_task_join(&producer_task);
    rt_task_join(&consumer_task);

    // 清理
    rt_task_delete(&consumer_task);
cleanup_producer:
    rt_task_delete(&producer_task);
cleanup_sem:
    rt_sem_delete(&sem);

    return EXIT_SUCCESS;
}
```

---

#### rt_sem_p

> int rt_sem_p (RT_SEM *sem, RTIME timeout);

等待信号量（带相对标量超时）。

此例程是 rt_sem_p_timed() 的变体，接受以标量值表示的相对超时规范。

**参数**

- **sem**: 信号量描述符。
- **timeout**: 以时钟滴答表示的延迟。传递 TM_INFINITE 会导致调用者无限期阻塞，直到请求被满足。传递 TM_NONBLOCK 会导致服务在请求无法立即满足的情况下返回而不阻塞。

**标签**

`xthread-nowait`, `switch-primary`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <alchemy/task.h>
#include <alchemy/sem.h>
#include <alchemy/timer.h>

#define TASK_PRIO 50
#define TASK_MODE T_JOINABLE
#define TASK_STKSZ 0

RT_TASK producer_task, consumer_task;
RT_SEM sem;
int data = 0;

void producer(void *arg)
{
    while (data < 3) {
        printf("Producer: Producing item\n");
        rt_task_sleep(1000000000);  // 睡眠 1 秒
        data++;
        rt_sem_v(&sem);
        printf("Producer: Item produced\n");
    }
}

void consumer(void *arg)
{
    while (data < 3) {
        printf("Consumer: Waiting for item\n");
        ret = rt_sem_p(&sem, TM_INFINITE);
        printf("Consumer: Item consumed, data = %d\n\n",data);
    }
}

int main(int argc, char *argv[])
{
    int ret;

    // 创建信号量
    ret = rt_sem_create(&sem, "MySemaphore", 0, S_FIFO);
    if (ret < 0) {
        printf("Error creating semaphore: %d\n", ret);
        return EXIT_FAILURE;
    }

    //  创建生产者任务
    ret = rt_task_create(&producer_task, "Producer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating producer task: %d\n", ret);
        goto cleanup_sem;
    }

    // 创建消费者任务
    ret = rt_task_create(&consumer_task, "Consumer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating consumer task: %d\n", ret);
        goto cleanup_producer;
    }

    // 启动任务
    rt_task_start(&producer_task, &producer, NULL);
    rt_task_start(&consumer_task, &consumer, NULL);

    // 等待任务完成
    rt_task_join(&producer_task);
    rt_task_join(&consumer_task);

    // 清理
    rt_task_delete(&consumer_task);
cleanup_producer:
    rt_task_delete(&producer_task);
cleanup_sem:
    rt_sem_delete(&sem);

    return EXIT_SUCCESS;
}
```

---

#### rt_sem_p_timed

> int rt_sem_p_timed (RT_SEM *sem, const struct timespec *abs_timeout);

等待信号量（带绝对时间超时）。

测试并递减信号量计数。如果信号量值大于零，则将其递减一，并立即返回给调用者。否则，调用者将被阻塞，直到信号量被发出或销毁，除非要求非阻塞操作。

**参数**

- **sem**: 信号量描述符。
- **abs_timeout**: 以秒/纳秒表示的绝对时间，基于 Alchemy 时钟，指定等待请求满足的时间限制。传递 NULL 会导致调用者无限期阻塞，直到请求被满足。传递 { .tv_sec = 0, .tv_nsec = 0 } 会导致服务在请求无法立即满足的情况下返回而不阻塞。

**返回值**

成功时返回零。否则：
- 如果在请求满足之前达到 abs_timeout，则返回 **-ETIMEDOUT**。
- 如果 abs_timeout 为 { .tv_sec = 0, .tv_nsec = 0 } 且进入时信号量计数为零，则返回 **-EWOULDBLOCK**。
- 如果在请求满足之前为当前任务调用了 rt_task_unblock()，则返回 **-EINTR**。
- 如果 sem 不是有效的信号量描述符，则返回 **-EINVAL**。
- 如果 sem 在调用者等待时被删除，则返回 **-EIDRM**。在这种情况下，返回时 sem 不再有效。
- 如果此服务应阻塞，但不是从 xkernel 线程调用的，则返回 **-EPERM**。

**标签**

`xthread-nowait`, `switch-primary`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <alchemy/task.h>
#include <alchemy/sem.h>
#include <alchemy/timer.h>

#define TASK_PRIO 50
#define TASK_MODE T_JOINABLE
#define TASK_STKSZ 0

RT_TASK producer_task, consumer_task;
RT_SEM sem;
int data = 0;

void producer(void *arg)
{
    while (data < 3) {
        printf("Producer: Producing item\n");
        if(data == 0) {
            rt_task_sleep(2000000000);  // 睡眠 2 秒, 触发超时
        }
        rt_task_sleep(1000000000);  // 睡眠 1 秒
        data++;
        rt_sem_v(&sem);
        printf("Producer: Item produced\n");
    }
}

void consumer(void *arg)
{
    struct timespec ts;
    int ret;

    while (data < 3) {
        printf("Consumer: Waiting for item\n");
        clock_gettime(CLOCK_MONOTONIC, &ts);
        ts.tv_sec += 2;  // 超时时间 2 秒
        ret = rt_sem_p_timed(&sem, &ts);
        if(ret == 0){
            printf("Consumer: Item consumed, data = %d\n\n",data);
        }else if(ret == -ETIMEDOUT)
        {
            printf("Consumer: Timeout while waiting for semaphore.\n");
        }else{
            printf("Consumer: Error while waiting for semaphore: %d\n", ret);
        }

    }
}

int main(int argc, char *argv[])
{
    int ret;

    // 创建信号量
    ret = rt_sem_create(&sem, "MySemaphore", 0, S_FIFO);
    if (ret < 0) {
        printf("Error creating semaphore: %d\n", ret);
        return EXIT_FAILURE;
    }

    //  创建生产者任务
    ret = rt_task_create(&producer_task, "Producer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating producer task: %d\n", ret);
        goto cleanup_sem;
    }

    // 创建消费者任务
    ret = rt_task_create(&consumer_task, "Consumer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating consumer task: %d\n", ret);
        goto cleanup_producer;
    }

    // 启动任务
    rt_task_start(&producer_task, &producer, NULL);
    rt_task_start(&consumer_task, &consumer, NULL);

    // 等待任务完成
    rt_task_join(&producer_task);
    rt_task_join(&consumer_task);

    // 清理
    rt_task_delete(&consumer_task);
cleanup_producer:
    rt_task_delete(&producer_task);
cleanup_sem:
    rt_sem_delete(&sem);

    return EXIT_SUCCESS;
}
```

---

#### rt_sem_p_until

> int rt_sem_p_until (RT_SEM *sem, RTIME abs_timeout);

等待信号量（带绝对标量超时）。

此例程是 rt_sem_p_timed() 的变体，接受以标量值表示的绝对超时规范。

**参数**

- **sem**: 信号量描述符。
- **abs_timeout**: 以时钟滴答表示的绝对时间。传递 TM_INFINITE 会导致调用者无限期阻塞，直到请求被满足。传递 TM_NONBLOCK 会导致服务在请求无法立即满足的情况下返回而不阻塞。

**标签**

`xthread-nowait`, `switch-primary`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <alchemy/task.h>
#include <alchemy/sem.h>
#include <alchemy/timer.h>

#define TASK_PRIO 50
#define TASK_MODE T_JOINABLE
#define TASK_STKSZ 0

RT_TASK producer_task, consumer_task;
RT_SEM sem;
int data = 0;

void producer(void *arg)
{
    while (data < 3) {
        printf("Producer: Producing item\n");
        if(data == 0) {
            rt_task_sleep(2000000000);  // 睡眠 2 秒, 触发超时
        }
        rt_task_sleep(1000000000);  // 睡眠 1 秒
        data++;
        rt_sem_v(&sem);
        printf("Producer: Item produced\n");
    }
}

void consumer(void *arg)
{
    RTIME timeout;
    int ret;

    while (data < 3) {
        printf("Consumer: Waiting for item\n");
        timeout = rt_timer_read() + 2000000000;  // 超时时间 2 秒
        ret = rt_sem_p_until(&sem, timeout);
        if(ret == 0){
            printf("Consumer: Item consumed, data = %d\n\n",data);
        }else if(ret == -ETIMEDOUT)
        {
            printf("Consumer: Timeout while waiting for semaphore.\n");
        }else{
            printf("Consumer: Error while waiting for semaphore: %d\n", ret);
        }

    }
}

int main(int argc, char *argv[])
{
    int ret;

    // 创建信号量
    ret = rt_sem_create(&sem, "MySemaphore", 0, S_FIFO);
    if (ret < 0) {
        printf("Error creating semaphore: %d\n", ret);
        return EXIT_FAILURE;
    }

    //  创建生产者任务
    ret = rt_task_create(&producer_task, "Producer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating producer task: %d\n", ret);
        goto cleanup_sem;
    }

    // 创建消费者任务
    ret = rt_task_create(&consumer_task, "Consumer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating consumer task: %d\n", ret);
        goto cleanup_producer;
    }

    // 启动任务
    rt_task_start(&producer_task, &producer, NULL);
    rt_task_start(&consumer_task, &consumer, NULL);

    // 等待任务完成
    rt_task_join(&producer_task);
    rt_task_join(&consumer_task);

    // 清理
    rt_task_delete(&consumer_task);
cleanup_producer:
    rt_task_delete(&producer_task);
cleanup_sem:
    rt_sem_delete(&sem);

    return EXIT_SUCCESS;
}
```

---

#### rt_sem_unbind

> int rt_sem_unbind (RT_SEM *sem);

解除信号量绑定。

**参数**

- **sem**: 信号量描述符。

此例程释放之前对信号量的绑定。此调用返回后，描述符将不再有效，无法再引用该对象。

**标签**

`thread-unrestricted`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <alchemy/task.h>
#include <alchemy/sem.h>
#include <alchemy/timer.h>

#define TASK_PRIO 50
#define TASK_MODE T_JOINABLE
#define TASK_STKSZ 0

RT_TASK producer_task, consumer_task;
RT_SEM sem;
int data = 0;

void producer(void *arg)
{
    RT_SEM sem_producer;
    
    int ret = rt_sem_bind(&sem_producer, "MySemaphore", TM_INFINITE);
    if (ret < 0) {
        printf("Error bind semaphore: %d\n", ret);
        return;
    }

    while (data < 3) {
        printf("Producer: Producing item\n");
        rt_task_sleep(1000000000);  // 睡眠 1 秒
        data++;
        rt_sem_v(&sem_producer);
        printf("Producer: Item produced\n");
    }

    ret = rt_sem_unbind(&sem_producer);
    if (ret < 0) {
        printf("Error unbind semaphore: %d\n", ret);
        return;
    }
}

void consumer(void *arg)
{
     RT_SEM sem_consumer;
    
    int ret = rt_sem_bind(&sem_consumer, "MySemaphore", TM_INFINITE);
    if (ret < 0) {
        printf("Error bind semaphore: %d\n", ret);
        return;
    }

    while (data < 3) {
        printf("Consumer: Waiting for item\n");
        rt_sem_p(&sem_consumer, TM_INFINITE);
        printf("Consumer: Item consumed, data = %d\n\n",data);
    }

    ret = rt_sem_unbind(&sem_consumer);
    if (ret < 0) {
        printf("Error unbind semaphore: %d\n", ret);
        return;
    }
}

int main(int argc, char *argv[])
{
    int ret;

    // 创建信号量
    ret = rt_sem_create(&sem, "MySemaphore", 0, S_FIFO);
    if (ret < 0) {
        printf("Error creating semaphore: %d\n", ret);
        return EXIT_FAILURE;
    }

    //  创建生产者任务
    ret = rt_task_create(&producer_task, "Producer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating producer task: %d\n", ret);
        goto cleanup_sem;
    }

    // 创建消费者任务
    ret = rt_task_create(&consumer_task, "Consumer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating consumer task: %d\n", ret);
        goto cleanup_producer;
    }

    // 启动任务
    rt_task_start(&producer_task, &producer, NULL);
    rt_task_start(&consumer_task, &consumer, NULL);

    // 等待任务完成
    rt_task_join(&producer_task);
    rt_task_join(&consumer_task);

    // 清理
    rt_task_delete(&consumer_task);
cleanup_producer:
    rt_task_delete(&producer_task);
cleanup_sem:
    rt_sem_delete(&sem);

    return EXIT_SUCCESS;
}
```

---

#### rt_sem_v

> int rt_sem_v (RT_SEM *sem);

发出信号量。

如果信号量处于挂起状态，等待队列中的任务将立即解除阻塞。否则，信号量计数将增加一，除非信号量以“脉冲”模式使用（参见 rt_sem_create()）。

**参数**

- **sem**: 信号量描述符。

**返回值**

成功时返回零。否则：
- 如果 sem 不是有效的信号量描述符，则返回 **-EINVAL**。

**标签**

`unrestricted`

示例代码

```c{filename="app.c"}
#include <stdio.h>
#include <stdlib.h>
#include <alchemy/task.h>
#include <alchemy/sem.h>
#include <alchemy/timer.h>

#define TASK_PRIO 50
#define TASK_MODE T_JOINABLE
#define TASK_STKSZ 0

RT_TASK producer_task, consumer_task;
RT_SEM sem;
int data = 0;

void producer(void *arg)
{
    while (data < 3) {
        printf("Producer: Producing item\n");
        rt_task_sleep(1000000000);  // 睡眠 1 秒
        data++;
        rt_sem_v(&sem);
        printf("Producer: Item produced\n");
    }
}

void consumer(void *arg)
{
    while (data < 3) {
        printf("Consumer: Waiting for item\n");
        rt_sem_p(&sem, TM_INFINITE);
        printf("Consumer: Item consumed, data = %d\n\n",data);
    }
}

int main(int argc, char *argv[])
{
    int ret;

    // 创建信号量
    ret = rt_sem_create(&sem, "MySemaphore", 0, S_FIFO);
    if (ret < 0) {
        printf("Error creating semaphore: %d\n", ret);
        return EXIT_FAILURE;
    }

    //  创建生产者任务
    ret = rt_task_create(&producer_task, "Producer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating producer task: %d\n", ret);
        goto cleanup_sem;
    }

    // 创建消费者任务
    ret = rt_task_create(&consumer_task, "Consumer", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    if (ret < 0) {
        printf("Error creating consumer task: %d\n", ret);
        goto cleanup_producer;
    }

    // 启动任务
    rt_task_start(&producer_task, &producer, NULL);
    rt_task_start(&consumer_task, &consumer, NULL);

    // 等待任务完成
    rt_task_join(&producer_task);
    rt_task_join(&consumer_task);

    // 清理
    rt_task_delete(&consumer_task);
cleanup_producer:
    rt_task_delete(&producer_task);
cleanup_sem:
    rt_sem_delete(&sem);

    return EXIT_SUCCESS;
}
```

---