一、信号量控制块:在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. tkinter的入门,估计也只能站门口

    from tkinter import * import tkinter.messagebox as messagebox #创建一个继承frame的类,是所有小部件(widget的容器) #widg ...

  2. Nginx初体验(一):nginx介绍

    今天我们来介绍一下Nginx. Nginx是一款轻量级的Web服务器/反向代理服务器以及电子邮件(IMAP/POP3)代理服务器 特点: 反向代理,负载均衡,动静分离 首先我们来介绍一下正向代理服务器 ...

  3. 北京Uber优步司机奖励政策(1月8日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  4. Java:当前线程运行完毕,再运行后续逻辑

    一.问题描述 在程序设计中,可能存在这样的情景:主线程中存在一个子线程,子线程需要在执行完毕后为后续代码逻辑提供参数.但在代码执行时,子进程还没执行完毕,后续的代码已经开始执行了,这时候就会出现参数为 ...

  5. SpringBoot-03:SpringBoot+Idea热部署

      ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 所谓热部署,就是在项目启动中,修改class类中做的修改操作,无需重新启动项目,就可以变更,在网页展示中有 ...

  6. ASP.NET MVC 微信JS-SDK认证

    layout: post title: ASP.NET MVC 微信JS-SDK认证 category: .net date: 2016-11-01 00:00:00 tags: .net javas ...

  7. DE1-SOC工程helloworld-第一篇(未完成)

    1. 参考官方的文档,第一个问题就是电脑上需要安装ubuntu虚拟机吗? 2. 创建一个“Hello world”工程:在Linux terminal 上打印信息. 3. 说是让安装个EDS软件,先去 ...

  8. HTTP请求中get和post的区别是什么

    GET和POST是Http请求中最常用的两种请求方法 首先介绍GET与POST的差异: (1)GET请求资源数据,POST向服务器传递需要处理的数据 (2)GET传递数据大小不超过2kb,POST没有 ...

  9. 211. String Permutation【LintCode by java】

    Description Given two strings, write a method to decide if one is a permutation of the other. Exampl ...

  10. 《Effective C++》读书笔记 被你忽略的关于构造析构赋值

    如果程序员没有定义,那么编译器会默认隐式为你创建一个copy构造函数,一个copy赋值操作符,一个析构函数.另外如果你没有声明任何构造函数,编译器会为你声明一个default构造函数. 但是只有当这些 ...