一、信号量控制块:在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内核之信号量的更多相关文章

  1. RT Thread 通过ENV来配置SFUD,操作SPI Flash

    本实验基于正点原子stm32f4探索者板子 请移步我的RT Thread论坛帖子. https://www.rt-thread.org/qa/forum.php?mod=viewthread& ...

  2. STM32 + RT Thread OS 学习笔记[二]

    串口通讯例程 通过上面的练习,对STM32项目开发有了一个直观印象,接下来尝试对串口RS232进行操作. 1.   目标需求: 开机打开串口1,侦听上位机(使用电脑串口测试软件)发送的信息,然后原样输 ...

  3. STM32 + RT Thread OS 串口通讯

    1.   创建项目 a)   禁用Finsh和console b)   默认情况下,项目文件包含了finsh,它使用COM1来通讯,另外,console输出(rt_kprintf)也使用了COM1.因 ...

  4. RT thread 设备驱动组件之USART设备

    本文以stm32f4xx平台介绍串口驱动,主要目的是:1.RTT中如何编写中断处理程序:2.如何编写RTT设备驱动接口代码:3.了解串行设备的常见处理机制.所涉及的主要源码文件有:驱动框架文件(usa ...

  5. STM32 + RT Thread OS 学习笔记[三]

    RTGUI 据说RTGUI是多线程的,因此与RT-Thread OS的耦合度较高,有可能要访问RT-Thread的线程控制块.如果要移植到其它OS,估计难度较大.目前还处于Alpha状态,最终将会包含 ...

  6. STM32 + RT Thread OS 学习笔记[四]

    1.  补注 a)      硬件,打通通讯通道 若学习者购买了学习板,通常可以在学习板提供的示例代码中找到LCD的相关驱动代码,基本上,这里的驱动的所有代码都可以从里面找到. 从上面的示意图可见,M ...

  7. RT Thread的SPI设备驱动框架的使用以及内部机制分析

    注释:这是19年初的博客,写得很一般,理解不到位也不全面.19年末得空时又重新看了RTThread的SPI和GPIO,这次理解得比较深刻.有时间时再整理上传. -------------------- ...

  8. RT Thread SPI设备 使用

    后记: 之前,我把SPI的片选在Cubemx中配置成了SPI_NSS.现在我给它改为了GPIO_OUTPUT.  同时参考了别人的类似的一个操作无线模块(采用SPI设备驱动)的例子程序(清楚了RTT的 ...

  9. linux内核剖析(十)进程间通信之-信号量semaphore

    信号量 什么是信号量 信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有. 信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0,说明它被占用,测试的线 ...

随机推荐

  1. android 8.0 Account行为变更 账号系统

    我们有个方法,是判断系统的账号有没有登录. public static boolean isAccountLogin(Context context) { String df = "com. ...

  2. 创龙DSP6748学习之RS485收发

    1. 先看下原理图,第一个问题,RS485其实就是使用的串口USART1,同时485的输出脚之间接120欧姆的电阻. 遇到个问题,为什么有两个使能引脚?还有RS485_A和RS485_B为什么分别接上 ...

  3. 『Golang』Go简介以及环境搭建

    简介 go语言是由Google进行维护的一个编程语言,发布自2009年.其以良好的编程风格.优秀的并发机制被广大的技术人员所接受. 使用go语言开发的优秀的产品: Docker gocode lime ...

  4. 「日常训练」Kefa and Dishes(Codeforces Round #321 Div. 2 D)

    题意与分析(CodeForces 580D) 一个人有\(n\)道菜,然后要点\(m\)道菜,每道菜有一个美味程度:然后给你了很多个关系,表示如果\(x\)刚好在\(y\)前面做的话,他的美味程度就会 ...

  5. docker官网安装

    最近发现一些同学居然不会安装docker,难,不难,只是“网络不好”! 如果是学习的话,目前我发现的比较好的方法还是到清华的开源镜像网站: https://mirror.tuna.tsinghua.e ...

  6. Python学习-猜数字游戏

    菩萨蛮·黄鹤楼 茫茫九派流中国,沉沉一线穿南北.烟雨莽苍苍,龟蛇锁大江. 黄鹤知何去,剩有游人处.把酒酹滔滔,心潮逐浪高! --coding:UTF-8-- import random secret ...

  7. (转载)Unity3d中的属性(Attributes)整理

    附加: float字段检视面板修改:[Range(1,10)] 对属性进行分组:[Header("xxx")] 工具栏中调用方法,类文件需在Editor文件夹中:[MenuIte( ...

  8. Pyhton网络爬虫实例_豆瓣电影排行榜_BeautifulSoup4方法爬取

    -----------------------------------------------------------学无止境------------------------------------- ...

  9. Struts2(十.在修改页显示照片列表并增加删除照片功能)

    一.显示照片列表功能 struts2中一般的处理方式:先在action中,准备数据,转到jsp中显示 1.UserAction /** * 点击修改用户按钮跳转到修改用户界面 * 为用户准备照片,以便 ...

  10. PNG和PVR之间互相转换的脚本

    项目经常会将png和pvr之间互相转换,这里mark一个脚本,会将当前目录下的文件全部批量转换 png转换成pvr @echo off path %path%;"C:\Program Fil ...