当前位置: 首页 > news >正文

【FreeRTOS】第八课(1):信号量(Semaphore)

目录

一、信号量的本质

信号量使用比喻

信号量使用

二、对比:普通队列和信号量队列

1.普通队列

2.信号量队列

小结

三、函数原型

1.创建

1)二值信号量

静态

动态

2)计数型信号量

静态

动态

2.删除

3.give

在普通任务中give

在ISR(中断)中give

4.take

在普通任务中take

在ISR中take

四、使用示例

五、优先级反转问题

优先级反转发生的逻辑


一、信号量的本质

信号:起提示作用

量:起计数作用

本质是一个不涉及数据传输,只涉及数据统计的队列,通过对信号量的使用可以实现任务的互斥操作

信号量使用比喻

将任务比喻成游客,信号比喻为票,票的数量就是信号量

take事件就是获得票,give事件就是增加票

如果有剩余的票,游客就能拿到票,同时票的数量减一

如果没有剩余的票,游客可以选择景区门口排队等待,vip游客先排队

景区可以增加票(give操作),让票的数量加一,同时唤醒等待的游客,每放一张票就唤醒一个等待的游客

每有一个游客离开景区可以选择保留票或把票上交(give操作),让票的数量加一

当票发到景区可以承载的上限时无需等待直接停止发票,同时返回发票失败的信息

信号量使用

如果有信号量,任务就能够执行,同时信号量减一

如果没有信号量,任务可以选择阻塞或者暂停,在阻塞过程中优先级高的任务会先获得信号量

在任务执行过程中可以使用give函数增加信号量,每增加一个信号量就会唤醒一个任务

每一个任务执行完毕可以选择保留或释放信号量(give操作,让信号量加一)

当信号量增加到上限就不再增加

二、对比:普通队列和信号量队列

1.普通队列

  • 有队列长度、读位置、写位置、计数值、发送者链表、接收者链表,用环形缓冲区保存数据,
  • 用send往队列里写数据,将数据写入环形缓冲区,计数值加一,提醒接收者有数据了,
  • 用receive读取队列里的数据,将数据从环形缓冲区读出并删除,计数值减一,提醒发送者有空位了

2.信号量队列

  • 有信号量最大值、计数值、接收者链表,无需环形缓冲区保存数据,
  • 增加信号量的操作叫做give,计数值加一,唤醒接收者有信号量可以使用了,
  • 其他任务使用信号量叫take,计数值减一,无需唤醒

小结

因为信号量队列不涉及数据的操作,所以相比于普通队列,信号量队列没有用于记录读写位置的指针,也没有读写数据的操作,但有接收者链表用于找到需要唤醒的任务

三、函数原型

数据类型解释

SemaphoreHandle_t信号量队列句柄,void*
StaticSemaphore_t一个操作系统已经给出的结构体
 UBaseType_t

unsigned long

BaseType_tlong
TickType_tuint32_t

1.创建

1)二值信号量

静态
/* 创建一个二进制信号量,返回它的句柄。* 此函数无需动态分配内存,所以需要先有一个StaticSemaphore_t结构体,并传入它的指针* 返回值: 返回句柄,非NULL表示成功*/
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer );
动态
/* 创建一个二进制信号量,返回它的句柄。* 此函数内部会分配信号量结构体 * 返回值: 返回句柄,非NULL表示成功*/
SemaphoreHandle_t xSemaphoreCreateBinary( void );

2)计数型信号量

静态
/* 创建一个计数型信号量,返回它的句柄。* 此函数无需动态分配内存,所以需要先有一个StaticSemaphore_t结构体,并传入它的指针* uxMaxCount: 最大计数值* uxInitialCount: 初始计数值,每消耗一个就减一* pxSemaphoreBuffer: StaticSemaphore_t结构体指针* 返回值: 返回句柄,非NULL表示成功*/
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer );
动态
/* 创建一个计数型信号量,返回它的句柄。* 此函数内部会分配信号量结构体 * uxMaxCount: 最大计数值* uxInitialCount: 初始计数值* 返回值: 返回句柄,非NULL表示成功*/
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);

2.删除

对于动态创建的信号量,不再需要它们时,可以删除它们以回收内存。

vSemaphoreDelete可以用来删除二进制信号量、计数型信号量,函数原型如下:

/** xSemaphore: 信号量句柄,你要删除哪个信号量*/
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

3.give

二进制信号量、计数型信号量的give函数是一样的,take函数也是一样的

在普通任务中give

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
参数说明
xSemaphore信号量句柄,释放哪个信号量
返回值pdTRUE表示成功, 如果二进制信号量的计数值已经是1,再次调用此函数则返回失败; 如果计数型信号量的计数值已经是最大值,再次调用此函数则返回失败

在ISR(中断)中give

BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore,BaseType_t *pxHigherPriorityTaskWoken);
参数说明
xSemaphore信号量句柄,释放哪个信号量
pxHigherPriorityTaskWoken如果释放信号量导致更高优先级的任务变为了就绪态, 则*pxHigherPriorityTaskWoken = pdTRUE
返回值pdTRUE表示成功, 如果二进制信号量的计数值已经是1,再次调用此函数则返回失败; 如果计数型信号量的计数值已经是最大值,再次调用此函数则返回失败

4.take

在普通任务中take

BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,TickType_t xTicksToWait);
参数说明
xSemaphore信号量句柄,获取哪个信号量
xTicksToWait如果无法马上获得信号量,阻塞一会: 0:不阻塞,马上返回 portMAX_DELAY: 一直阻塞直到成功 其他值: 阻塞的Tick个数,可以使用*pdMS_TO_TICKS()*来指定阻塞时间为若干ms
返回值pdTRUE表示成功

在ISR中take

BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,BaseType_t *pxHigherPriorityTaskWoken);
参数说明
xSemaphore信号量句柄,获取哪个信号量
pxHigherPriorityTaskWoken如果获取信号量导致更高优先级的任务变为了就绪态, 则*pxHigherPriorityTaskWoken = pdTRUE
返回值pdTRUE表示成功

四、使用示例

static SemaphoreHandle_t g_xSemTicks;     //用于接收信号量队列创建函数的返回值static void CarTask(void *params)
{/* 获得信号量,take */xSemaphoreTake(g_xSemTicks, portMAX_DELAY);/* 释放信号量,give *//* 当信号量被释放后,其他任务可以获得信号量执行,从而实现了互斥操作 */xSemaphoreGive(g_xSemTicks);vTaskDelete(NULL);
}void car_game()
{/* 创建动态信号量队列,最大值为3,初始值为1 *//* 意味着同时只有一个任务可以得到执行 *//* 类似于直接创建二值信号量 g_xSemTicks = xSemaphoreCreateBinary(); */g_xSemTicks = xSemaphoreCreateCounting(3, 1); /* 创建三个汽车任务 */xTaskCreate(CarTask, "car1", 128, &g_cars[0], osPriorityNormal, NULL);xTaskCreate(CarTask, "car2", 128, &g_cars[1], osPriorityNormal, NULL);xTaskCreate(CarTask, "car3", 128, &g_cars[2], osPriorityNormal, NULL);
}

五、优先级反转问题

有低中高三个优先级的任务,如果任务创建顺序是高中低,信号量是二值信号量,其中低优先级和高优先级的任务需要信号量才能执行,中优先级的任务无需信号量便能执行

优先级反转发生的逻辑

  1. 低优先级的任务最后创建,所以最先得到执行,执行一小段时间后发生任务切换,去寻找可以执行的任务,
  2. 由于高优先级的任务需要得到信号量才能执行,所以跳过执行高优先级的任务去执行中优先级的任务,
  3. 中优先级的任务执行一小段时间后发生任务切换,但是只会从中优先级切换到高优先级,永远不会切换回低优先级,信号量始终保持在低优先级任务内得不到释放,高优先级任务虽然能被切换,但也永远得不到执行

发生了优先级低的任务阻塞了优先级高的任务,这就是优先级反转

http://www.dtcms.com/a/440646.html

相关文章:

  • 广州网站建设网站开发怎么做多语言网站
  • 重庆专业做淘宝网站抖音代运营排名
  • 怎么让自己的网站稍微变前面点中国互联网排名前十的公司
  • 佛山营销网站建设费用东莞专业做外贸网站的公司
  • 【LLM】基于ms-Swift大模型SFT和RL的训练实践
  • 做网站需要具备的基础条件江苏徐州工程交易网
  • 好的app设计网站有哪些开发公司英文
  • 做淘宝优惠网站步骤江苏城乡建设部网站首页
  • 北京南站列车时刻表wordpress link rel
  • 没有任何收录的网站做SEM有用吗网站站外推广的内外链接怎么做
  • 做极速赛车网站多用户商城系统
  • 网站开发使用软件环境网站图片速度
  • 网站首页该怎么做什么网站可以做名片
  • 企业网站 留言板软件开发工具包括
  • 上海网站制作网网站建设课程教学改革
  • 做网站的 深圳做淘宝客建网站用什么
  • 网站建设价格女高端模板网站建设
  • 石家庄大的网站开发公司河南做网站的费用
  • 东莞政务网站建设方案wordpress手机视频
  • 旅游网站前台怎么做网站后台 二级域名
  • 北京建设电工证查询网站文库百度登录入口
  • 网站制作需求表做生意必定红火的公司名字
  • 求推荐在哪个网站做德语翻译员网站开发团队分工
  • 网站商城建设的维度网站建设与管理学什么
  • 中国建设银行公司网站官网申请个网站要多少钱
  • 腾讯云如何建设网站长春火车站是哪个区
  • 做网站分前台后端吗wordpress多站点配置教程
  • 苏州做网站的哪个公司比较好建设网站用哪个主机好
  • 服务器怎么做网站教程门户网站的主要特点
  • 网站开发主要学些什么软件网页设计实训总结100字