RT-thread内核之信号量
一、信号量控制块:在include/rtdef.h中
#ifdef RT_USING_SEMAPHORE
/**
* Semaphore structure
*/
struct rt_semaphore
{
struct rt_ipc_object parent; /**< inherit from ipc_object *///派生自IPC对象 rt_uint16_t value; /**< value of semaphore. */ //信号量计数器
};
typedef struct rt_semaphore *rt_sem_t;
#endif
信号量是用来解决线程同步和互斥的通用工具,和互斥量类似,信号量也可用作资源互斥访问,但信号量没有所有者的概念,在应用上比互斥量更广泛。信号量比较简单,不能解决优先级翻转问题,但信号量是一种轻量级的对象,比互斥量小巧、灵活。因此在很多对互斥要求不严格的系统中(或者不会造成优先级翻转的情况下),经常使用信号量来管理互斥资源。value为信号计数器,此信号量多次被释放时将会累加,在被获取时则将减1,当其值为0时,再请求获取的线程将会被挂起到挂起链表中。
二、信号量相关接口:在src/ipc.c中
创建动态信号量:
rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag);
当调用这个函数时,系统将先分配一个semaphore对象,并初始化这个对象,然后初始化IPC对象以及与semaphore相关的部分。在创建信号量指定的参数中,信号量标志参数决定了当信号量不可用时,多个线程等待的排队方式。当选择FIFO方式时,那么等待线程队列将按照先进先出的方式排队,先进入的线程将先获得等待的信号量;当选择PRIO(优先级等待)方式时,等待线程队列将按照优先级进行排队,优先级高的等待线程将先获得等待的信号量。 删除动态信号量:
rt_err_t rt_sem_delete(rt_sem_t sem);
调用这个函数时,系统将删除这个信号量。如果删除该信号量时,有线程正在等待该信号量,那么删除操作会先唤醒所有等待在该信号量上的线程(所有等待线程的error返回值是-RT_ERROR,表明为异常唤醒),然后再释放信号量的内存资源。
初始化静态信号量:
rt_err_t rt_sem_init(rt_sem_t sem,
const char *name,
rt_uint32_t value,
rt_uint8_t flag);
当调用这个函数时,系统将对这个semaphore对象进行初始化,然后初始化IPC对象以及与semaphore相关的部分。在初始化信号量指定的参数中,信号量标志参数决定了当信号量不可用时,多个线程等待的方式。当选择FIFO方式时,那么等待线程队列将按照先进先出的方式排队,先进入的线程将先获得等待的信号量;当选择PRIO(优先级等待)方式时,等待线程队列将按照优先级进行排队,优先级高的等待线程将先获得等待的信号量。 脱离静态信号量:
rt_err_t rt_sem_detach(rt_sem_t sem);
使用该函数后,内核先唤醒所有挂在该信号量等待队列上的所有线程,然后将该信号量从内核对象管理器中删除。原来挂起在信号量上的所有等待线程error值将获得-RT_ERROR 的返回值。
获取信号量:
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time);
线程通过获取信号量来获得信号量资源实例,当信号量值大于零时,线程将获得信号量,并且相应的信号量值都会减1。
在调用这个函数时,如果信号量的值等于零,那么说明当前信号量资源实例不可用,申请该信号量的线程将根据time参数的情况选择直接返回、或挂起等待一段时间、或永久等待,直到其他线程或中断释放该信号量。如果在参数time指定的时间内依然得不到信号量,线程将超时返回,返回值是-RT_ETIMEOUT。
获取信号量函数首先会判断当前是否有信号量(通过value值是否大于0来判断),如果有则立即成功返回,如果没有,则接下来首先判断是否有时间参数,如果等待时间参数为0,则表示需要立即返回,则立即返回错误。如果等待时间参数大于0,则表示需要延时一段时间,在此延时期间,如何信号量到达,或者信号量被非法脱离,或一直没有等到,则通过判断线程的error值来判断当前是否已经成功获得信号值,因为如果成功获得信号量时,即在另一个线程release信号后,因此这一整个过程并没有修改线程的error值,因此,线程的error值一直保持原先的RT_EOK不变。若是线程一直没有等待到信号量的到达,即产生的定时器超时时(在take过程中会将设置一定时器,然后启动它,再挂起当前线程),在线程定时器的回调超时处理函数中,程序会将线程的error值修改为-RT_ETIMEOUT。另,如果之前讲解脱离线程时,如果在某一线程等待信号量期间,这个信号量被意外脱离了时,在脱离信号量的函数中,程序会将线程的error值修改为-RT_ERROR。综上所述,程序可以通过线程的error值来对其是否真正获得信号量进行判定,即如果线程的error值一直保持原样即thread->error==RT_EOK时,则为已获取信号量,否则没有获取,要么超时(-RT_ETIMEOUT),要么非法脱离(-RT_ERROR)了。
无等待获取信号量:
rt_err_t rt_sem_trytake(rt_sem_t sem);
当用户不想在申请的信号量上挂起线程进行等待时,可以使用无等待方式获取信号量,这个函数与rt_sem_take(sem, 0) 的作用相同,即当线程申请的信号量资源实例不可用的时候,它不会等待在该信号量上,而是直接返回-RT_ETIMEOUT。 释放信号量:
rt_err_t rt_sem_release(rt_sem_t sem);
当线程完成资源的访问后,应尽快释放它持有的信号量,使得其他线程能获得该信号量。当信号量的值等于零时,并且有线程等待这个信号量时,将唤醒等待在该信号量线程队列中的第一个线程,由它获取信号量。否则将把信号量的值加1。
控制信号量:
rt_err_t rt_sem_control(rt_sem_t sem, rt_uint8_t cmd, void *arg);
对于cmd,在rtdef.h中只定义了#define RT_IPC_CMD_RESET这一条有效命令,即重新设置信号量值value,同时唤醒所有等待该信号量的线程,参数arg的值为新的信号量值。
只支持重置信号量,此时若其存在挂起线程,则将其全部唤醒再次重新调度。此时在rt_ipc_list_resume_all函数中会将所有挂起的线程的error值设置为-RT_ERROR.
RT-thread内核之信号量的更多相关文章
- RT Thread 通过ENV来配置SFUD,操作SPI Flash
本实验基于正点原子stm32f4探索者板子 请移步我的RT Thread论坛帖子. https://www.rt-thread.org/qa/forum.php?mod=viewthread& ...
- STM32 + RT Thread OS 学习笔记[二]
串口通讯例程 通过上面的练习,对STM32项目开发有了一个直观印象,接下来尝试对串口RS232进行操作. 1. 目标需求: 开机打开串口1,侦听上位机(使用电脑串口测试软件)发送的信息,然后原样输 ...
- STM32 + RT Thread OS 串口通讯
1. 创建项目 a) 禁用Finsh和console b) 默认情况下,项目文件包含了finsh,它使用COM1来通讯,另外,console输出(rt_kprintf)也使用了COM1.因 ...
- RT thread 设备驱动组件之USART设备
本文以stm32f4xx平台介绍串口驱动,主要目的是:1.RTT中如何编写中断处理程序:2.如何编写RTT设备驱动接口代码:3.了解串行设备的常见处理机制.所涉及的主要源码文件有:驱动框架文件(usa ...
- STM32 + RT Thread OS 学习笔记[三]
RTGUI 据说RTGUI是多线程的,因此与RT-Thread OS的耦合度较高,有可能要访问RT-Thread的线程控制块.如果要移植到其它OS,估计难度较大.目前还处于Alpha状态,最终将会包含 ...
- STM32 + RT Thread OS 学习笔记[四]
1. 补注 a) 硬件,打通通讯通道 若学习者购买了学习板,通常可以在学习板提供的示例代码中找到LCD的相关驱动代码,基本上,这里的驱动的所有代码都可以从里面找到. 从上面的示意图可见,M ...
- RT Thread的SPI设备驱动框架的使用以及内部机制分析
注释:这是19年初的博客,写得很一般,理解不到位也不全面.19年末得空时又重新看了RTThread的SPI和GPIO,这次理解得比较深刻.有时间时再整理上传. -------------------- ...
- RT Thread SPI设备 使用
后记: 之前,我把SPI的片选在Cubemx中配置成了SPI_NSS.现在我给它改为了GPIO_OUTPUT. 同时参考了别人的类似的一个操作无线模块(采用SPI设备驱动)的例子程序(清楚了RTT的 ...
- linux内核剖析(十)进程间通信之-信号量semaphore
信号量 什么是信号量 信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有. 信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0,说明它被占用,测试的线 ...
随机推荐
- nmap教程(上)
一.nmap的主要功能 1.端口扫描 2.主机探测:查找目标网络的在线主机 3.服务/版本检测:发现开放端口后,进一步检测目标主机的检测服务协议.应用程序名称.版本号等信息 4.操作系统检测 5.网络 ...
- Unknown host 'services.gradle.org' 解决方法
报错如下: Unknown host 'services.gradle.org'. You may need to adjust the proxy settings in Gradle. Learn ...
- XSS----payload,绕过,xss小游戏记录
一.XSS 1.原理:攻击者把恶意的脚本代码注入到网页中,等待其他用户浏览 这些网页(或触发其他条件),从而执行其中的恶意代码. 1.xss实例代码: test.html <!DOCTYPE h ...
- 只写Python一遍代码,就可以同时生成安卓及IOS的APP,真优秀
前言: 用Python写安卓APP肯定不是最好的选择,但是肯定是一个很偷懒的选择 我们使用kivy开发安卓APP,Kivy是一套专门用于跨平台快速应用开发的开源框架,使用Python和Cython编写 ...
- 使用SpringBoot整合ssm项目
SpringBoot是什么? Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程. Spring Boot 现在已经成为Java ...
- 对Java对象的认识与理解
今天是我学习编程以来第一次写博客,记下平日学习所得,本来这几日都在学习web框架 但觉得梳理一下之前所学很有必要.毕竟之前学习Java感觉很粗略只是以考试为目的.所以就以<Thinking in ...
- Open MPI集群运行
部署完之后,代码也能正确跑起来了,也确实集群分散了.跑一下各种各样的代码,发现了一个错误: $ ~/OpenMpi/bin/mpiexec -np ~/NetWorkTest My rank is M ...
- OpenMPI 集群配置
现在有2台机器,希望可以尝试一下在多台机器上跑MPI的感觉,所以跑之前就得配置,先参考网址: https://www.cnblogs.com/awy-blog/p/3402949.html: 1. 配 ...
- Docker 镜像构建的时候,应该小心的坑
不要改文件 如果run了以后,你还需要进入到容器中,修改容器的配置,那么,这个容器是危险的.一旦容器无法启动,就再也改不了配置.那么你就需要删除和重新run这个容器,而配置要再改一遍.一个可用的镜像在 ...
- aishell数据处理为thchs30格式
目录 aishell数据转换格式 aishell数据转化方法 aishell数据格式对于用神经网络处理数据的同学来说比较不友善,因为他只有文字转录和音素级别的转录,并没有拼音的转录. 而thchs30 ...