菜单

Cobalt/Semaphore services

详细描述

计数信号量 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
  • 如果此服务应阻塞,但不是从 Xenomai 线程调用的,则返回 -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
  • 如果此服务从无效上下文(例如中断或非 Xenomai 线程)调用,则返回 -EPERM

标签

xthread-only, mode-unrestricted, switch-secondary

注意

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

示例代码

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 不再有效。
  • 如果此服务应阻塞,但不是从 Xenomai 线程调用的,则返回 -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;
}

最近修改: 2025-07-24