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,说明它被占用,测试的线 ...
随机推荐
- MongoDB入门---文档查询操作之条件查询&and查询&or查询
经过前几天的学习之路,今天终于到了重头戏了.那就是文档查询操作.话不多说哈,直接看下语法: db.collection.find(query, projection) query :可选,使用查询操作 ...
- Java基础—ArrayList源码浅析
注:以下源码均为JDK8的源码 一. 核心属性 基本属性如下: 核心的属性其实是红框中的两个: //从注释也容易看出,一个是集合元素,一个是集合长度(注意是逻辑长度,即元素的个数,而非数组长度) 其中 ...
- 北京Uber优步司机奖励政策(4月2日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 使用Google Cloud Messaging (GCM),PHP 开发Android Push Notifications (安卓推送通知)
什么是GCM? Google Cloud Messaging (GCM) 是Google提供的一个服务,用来从服务端向安卓设备发送推送通知. GCM分为客户端和服务端开发. 这里我们只介绍服务端开发 ...
- 使用PowerDesign15反向生成数据库
在Pd15中建立物理模型后,可以通过反向工程直接生成数据库的表结构.主要有以下几个步骤: 1. 首先设置一下数据库配置,选择对应要使用的数据库(此处选择Sql Server 2008 R ...
- andriod 学习三 使用android资源
3.1 android框架中有许多资源,包括布局,字符串,位图,图片....,使用资源之前需要在相应的资源文件中定义资源,然后编译程序时ADT将定义的资源转换成java类并给予唯一的id,而代码中需要 ...
- apache Subversion 直接支持LDAP域群组
如果你的Subversion已经用apache的ldap支持用户认证功能,你是否常常在想,既然都用ldap支持认证,为什么不直接支持域群组, 反而在authz文件里面一个一个的手工定义,或者有人用脚本 ...
- 阿里云中linux 下svn服务器安装
摘要: 安装步骤如下: 1.yum install subversion 2.输入rpm -ql subversion查看安装位置,如下图: 我们知道svn在bin目录下生成了几个二进制文件. 输 ...
- requests,lxml爬启信宝
首先, 添加requests模块: 然后, 添加lxml模块: 启信宝登录抓包: QiXinBao.py: import requestsfrom lxml import etree loginUrl ...
- Linux用户及权限
库:lib 共享库:.so ,shared object, 权限: 用户,获取资源,服务的标识符 组,指派权限,标识符 进程:以某个用户的身份在进行,有属主和属组 安全上下文(security con ...