2)信号量
信号量是一种实现任务间同步的机制,一般用于多个任务间有限资源竞争访问。
通常来说,一个信号量中持有一个整形数值,用以表示可用资源的数量。当一个信号量的可用资源数量大于0时,任务尝试获取该信号量成功,信号量的可用资源数减一;当一个信号量的可用资源数等于0时,任务尝试获取该信号量失败或进入阻塞状态。信号量的这一模式,当可用资源数为1时,可将其用于资源的互斥访问;或者解决生产者-消费者问题中的资源生产-消费问题。编程实例章节会演示生产者-消费者问题的解决范式。
信号量semaphore
tos_sem_create
k_err_t tos_sem_create(k_sem_t *sem, k_sem_cnt_t init_count);
• 功能描述
创建一个信号量。
• 参数解释
IN/OUT 参数名 描述
[in] sem 信号量句柄
[in] init_count 信号量初始量
• 返回值
K_ERR_NONE 信号量创建成功。
K_ERR_OBJ_PTR_NULL sem指针为空。
tos_sem_destroy
k_err_t tos_sem_destroy(k_sem_t *sem);
• 功能描述
销毁一个信号量。
• 参数解释
IN/OUT 参数名 描述
[in] sem 信号量数据结构指针
• 返回值
K_ERR_NONE 信号量销毁成功。
K_ERR_OBJ_INVALID sem指向的不是一个合法的信号量。
K_ERR_OBJ_PTR_NULL sem指针为空。
tos_sem_pend
k_err_t tos_sem_pend(k_sem_t *sem, k_tick_t timeout);
• 功能描述
尝试获取一个信号量。
• 参数解释
IN/OUT 参数名 描述
[in] sem 信号量句柄
[in] timeout 等待超时参数
• 返回值
K_ERR_NONE 获取信号量成功。
K_ERR_PEND_NOWAIT 获取信号量失败(信号量资源不足),同时timeout参数为TOS_TIME_NOWAIT(表示获取不到信号量时立即返回)
K_ERR_PEND_SCHED_LOCKED 获取信号量失败,同时系统调度处于锁定状态。
K_ERR_PEND_TIMEOUT 在timeout超时范围内未获取到信号量。
K_ERR_PEND_DESTROY 试图获取的信号量被销毁了(tos_sem_destroy)
tos_sem_post
k_err_t tos_sem_post(k_sem_t *sem);
• 功能描述
释放信号量,并唤醒等待队列上的一个任务。如果有多个任务在此信号量的等待队列上,唤醒优先级最高的任务。
• 参数解释
IN/OUT 参数名 描述
[in] sem 信号量句柄
• 返回值
K_ERR_NONE 信号量释放成功。
K_ERR_SEM_OVERFLOW 信号量值溢出。
tos_sem_post_all
k_err_t tos_sem_post_all(k_sem_t *sem);
• 功能描述
释放信号量,并唤醒等待队列上的所有任务。
• 参数解释
IN/OUT 参数名 描述
[in] sem 信号量句柄
• 返回值
K_ERR_NONE 信号量释放成功。
K_ERR_SEM_OVERFLOW 信号量值溢出。
其实就是反应资源的多少,比如我们经常会遇到的图像采集与显示,可以通过这个方法来同步
编程实例:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "string.h"
#include "cmsis_os.h"
#include "tos.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:");
printf("%d\n", salt);
resource.buffer[resource.cursor++] = salt;
printf("\n");
}
void entry_task_producer(void *arg)
{
size_t salt = 0;
k_err_t err;
while (1)
{
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\n", resource.buffer[--resource.cursor]);
printf("\n");
}
void entry_task_consumer(void *arg)
{
k_err_t err;
while (1)
{
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)
{
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(360,25,2,8); //设置时钟,180Mhz
delay_init(180); //初始化延时函数
uart_init(115200); //初始化USART
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
LCD_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,
1,
stack_task_producer,
STK_SIZE_TASK_PRODUCER,
0);
(void)tos_task_create(&task_consumer,
"consumer",
entry_task_consumer,
NULL,
2,
stack_task_consumer,
STK_SIZE_TASK_CONSUMER,
0);
tos_knl_start();
while(1)
{}
}
实验现象:
每隔一段时间生产者写一组数,消费者消耗一组数