信号量
概述
信号量是一种实现任务间同步的机制,一般用于多个任务间有限资源竞争访问。
通常来说,一个信号量中持有一个整形数值,用以表示可用资源的数量。当一个信号量的可用资源数量大于0时,任务尝试获取该信号量成功,信号量的可用资源数减一;当一个信号量的可用资源数等于0时,任务尝试获取该信号量失败或进入阻塞状态。信号量的这一模式,当可用资源数为1时,可将其用于资源的互斥访问;或者解决生产者-消费者问题中的资源生产-消费问题。编程实例章节会演示生产者-消费者问题的解决范式。
API讲解
编程实例
1、在tos_config.h中,配置信号量组件开关TOS_CFG_SEM_EN:
#define TOS_CFG_SEM_EN 1u
2、编写main.c示例代码:
#include "tos.h" #include "mcu_init.h" #define STK_SIZE_TASK_PRODUCER 512 #define STK_SIZE_TASK_CONSUMER 512 k_stack_t stack_task_producer[STK_SIZE_TASK_PRODUCER]; k_stack_t stack_task_consumer[STK_SIZE_TASK_CONSUMER]; k_task_t task_producer; k_task_t task_consumer; extern void entry_task_producer(void *arg); extern void entry_task_consumer(void *arg); k_mutex_t buffer_locker; k_sem_t full; k_sem_t empty; #define RESOURCE_COUNT_MAX 3 struct resource_st { int cursor; uint32_t buffer[RESOURCE_COUNT_MAX]; } resource = { 0, {0} }; static void produce_item(int salt) { printf("produce item:\n"); printf("%d", salt); resource.buffer[resource.cursor++] = salt; printf("\n"); } void entry_task_producer(void *arg) { size_t salt = 0; k_err_t err; while (K_TRUE) { err = tos_sem_pend(&empty, TOS_TIME_FOREVER); if (err != K_ERR_NONE) { continue; } err = tos_mutex_pend(&buffer_locker); if (err != K_ERR_NONE) { continue; } produce_item(salt); tos_mutex_post(&buffer_locker); tos_sem_post(&full); tos_task_delay(1000); ++salt; } } static void consume_item(void) { printf("cosume item:\n"); printf("%d\t", resource.buffer[--resource.cursor]); printf("\n"); } void entry_task_consumer(void *arg) { k_err_t err; while (K_TRUE) { err = tos_sem_pend(&full, TOS_TIME_FOREVER); if (err != K_ERR_NONE) { continue; } tos_mutex_pend(&buffer_locker); if (err != K_ERR_NONE) { continue; } consume_item(); tos_mutex_post(&buffer_locker); tos_sem_post(&empty); tos_task_delay(2000); } } int main(void) { board_init(); tos_knl_init(); tos_mutex_create(&buffer_locker); tos_sem_create(&full, 0); tos_sem_create(&empty, RESOURCE_COUNT_MAX); (void)tos_task_create(&task_producer, "producer", entry_task_producer, NULL, 4, stack_task_producer, STK_SIZE_TASK_PRODUCER, 0); (void)tos_task_create(&task_consumer, "consumer", entry_task_consumer, NULL, 4, stack_task_consumer, STK_SIZE_TASK_CONSUMER, 0); tos_knl_start(); }
运行效果
produce iterm: 0 cosume iterm: 0 produce iterm: 1 produce iterm: 2 cosume iterm: 2 produce iterm: 3 produce iterm: 4 cosume iterm: 4 produce iterm: 5 cosume iterm: 5 produce iterm: 6 cosume iterm: 6 produce iterm: 7 cosume iterm: 7 produce iterm: 8 cosume iterm: 8 produce iterm: 9 cosume iterm: 9 produce iterm: 10
[实例代码](./code/2.3.2 semaphore/main.c)