信号量
信号量 是实现传统计数信号量的内核对象。
概念
可以定义任意数量的信号量(仅受可用 RAM 限制)。每个信号量都通过其内存地址引用。
信号量具有以下主要属性:
计数,表示可以获取该信号量的次数。计数为零表示信号量不可用。
上限,表示信号量计数可以达到的最大值。
信号量必须初始化后才能使用。其计数必须设为非负值,且不大于上限。
线程或 ISR 均可 释放 信号量。释放信号量会使其计数加一,除非计数已经达到上限。
线程可以 获取 信号量。获取信号量会使其计数减一,除非信号量不可用(即计数为零)。信号量不可用时,线程可以选择等待它被释放。任意数量的线程都可以同时等待一个不可用的信号量。信号量被释放后,将由优先级最高且等待时间最长的线程获取。
备注
可以将信号量初始化为“满”状态(计数等于上限),以限制能够同时执行临界区的线程数。也可以将信号量初始化为空(计数为 0,上限大于 0),使所有等待线程都必须等到信号量计数增加后才能通过。常见信号量的所有标准用法均受支持。
备注
内核允许 ISR 获取信号量,但信号量不可用时,ISR 不得尝试等待。
实现
定义信号量
信号量使用 k_sem 类型的变量定义,随后必须调用 k_sem_init() 进行初始化。
以下代码定义一个信号量,并将计数设为 0、上限设为 1,使其成为二值信号量。
struct k_sem my_sem;
k_sem_init(&my_sem, 0, 1);
也可以使用 K_SEM_DEFINE 在编译时定义并初始化信号量。
以下代码与上面的代码片段效果相同。
K_SEM_DEFINE(my_sem, 0, 1);
释放信号量
调用 k_sem_give() 可以释放信号量。
以下代码延续上面的示例,释放信号量,表示已有一份数据可供消费者线程处理。
void input_data_interrupt_handler(void *arg)
{
/* notify thread that data is available */
k_sem_give(&my_sem);
...
}
获取信号量
调用 k_sem_take() 可以获取信号量。
以下代码延续上面的示例,等待信号量被释放,最长等待 50 毫秒。如果未能及时获取信号量,则发出警告。
void consumer_thread(void)
{
...
if (k_sem_take(&my_sem, K_MSEC(50)) != 0) {
printk("Input data not available!");
} else {
/* fetch available data */
...
}
...
}
使用建议
使用信号量控制多个线程对一组资源的访问。
使用信号量在生产者和消费者线程或 ISR 之间同步处理过程。
配置选项
相关配置选项:
无。
API 参考
用户模式信号量 API 参考
sys_sem 位于用户内存中,启用用户模式时,它为用户模式线程提供计数信号量功能。未启用用户模式时,sys_sem 的行为与 k_sem 相同。