信号量的操作及原理

 
1.OSSemCreate创建信号量semaphore
    在使用信号量之前,要先用OSSemCreate创建一个信号量,并通过返回的合法事件结构体指针使用信号量。
  1. OS_EVENT *OSSemCreate(INT16U cnt)
  2. {
  3. #if OS_CRITICAL_METHOD == 3 /* 原理请查看http://blog.csdn.net/liuhui_8989/article/details/8783323 */
  4. OS_CPU_SR cpu_sr;
  5. #endif
  6. OS_EVENT *pevent;
  7. if(OSIntNesting>0){/* 不能在中断内创建信号量 */
  8. return((OS_EVENT *)0);/* 直接返回0 */
  9. }
  10. OS_ENTER_CRITICAL();
  11. pevent =OSEventFreeList;/* 获取空闲的事件控制块 */
  12. if(OSEventFreeList!=(OS_EVENT *)0){/* 将OSEventFreeList指向下一个事件控制块 */
  13. OSEventFreeList=(OS_EVENT *)OSEventFreeList->OSEventPtr;
  14. }
  15. OS_EXIT_CRITICAL();
  16. if(pevent !=(OS_EVENT *)0){/* Get an event control block */
  17. pevent->OSEventType= OS_EVENT_TYPE_SEM;
  18. pevent->OSEventCnt= cnt;/* 设置计数器的初值 */
  19. pevent->OSEventPtr=(void*)0;/* Unlink from ECB free list */
  20. OS_EventWaitListInit(pevent);/* 初始化事件控制块中任务等待表为0 */
  21. }
  22. return(pevent);
  23. }
    简而言之,如果没有了空闲的事件控制块或者是在中断内创建信号里,则返回无效的事件控制块0;否则返回类型为信号量,任务等待表OSEventGrp和OSEventTbl[]为0,且已设置了计数器初值的事件控制块指针。这样便成功地创建了一个信号量。这里要注意,使用OSSemCreate函数返回的指针前,要检验是否为有效的指针。

    cnt的值至少为0。
    创建了信号量之后,便可以对信号量进行如下操作了,申请、释放、删除、查询信号量。
2. 信号量的申请和释放
  1. 申请:voidOSSemPend(OS_EVENT *pevent, INT16U timeout, INT8U *err)
  2. 释放:INT8U OSSemPost(OS_EVENT *pevent)
    OSSemPend函数有三个参数,
    第一个是一个指向事件控制块的指针,该值为OSSemCreate返回值。
    第二个是一个等待时间值(至少为0),如果信号量目前被占用,则无法立即申请到信号量,调用该函数的任务将被挂起,如果等待时间值为0,则一直被挂起直到信号量被释放为止(OSSemPost能够在释放信号量的同时,恢复等待信号量的任务),如果等待时间值大于0,则在超时时间过后,由OSTineTick恢复为就绪状态的任务。

    第三个为一个指向错误代码的指针,该值作为函数返回值使用。
    OS_NO_ERR                       函数调用成功,获得了信号量。
    OS_TIMEOUT                     在规定的时间内没有申请到信号量
    OS_ERR_EVENT_TYPE       事件类型错误,不是信号量
    OS_ERR_PEND_ISR            不能在中断内申请信号量
    OS_ERR_PEVENT_NULL    pevent指针无效
 
下面讲解一下函数内部原理:
    如果信号量的计数器值大于0,则将其减1,表示又有一个任务占用,并直接返回。
    如果信号量的计数器值为0,表示信号量已被其他任务占用,此时任务控制块中的状态标志是等待信号状态以及就绪的,因为使用的是按位或操作,保留了原有的就绪状态标志。
    之后调用了OS_EventTaskWait(pevent); 此时作了3件事:
    (1)OSTCBCur->OSTCBEventPtr = pevent;将事件控制块指针保存于任务控制块中
    (2)去除任务在任务就绪表的就绪状态,注意没有包括任务控制块中的状态标志
    (3)设置事件控制块中的任务等待表
    至此任务被挂起!通过OS_Sched运行其他任务去了。
    接下来的结果取决于,信号量是否在规定的等待时间内被释放。
    在当前任务被挂起,而运行其他任务的同时,每个时钟节拍都会运行OSTimeTick中断函数,此函数会遍历所有任务,如果任务控制块中的状态标志为就绪的,且Dly等待值不为0,则将Dly减1,如果减1后刚好为0,则在任务就绪表中恢复该任务的就绪状态!
    如果该就绪状态的任务恢复运行,此时任务控制块的状态标志仍为OS_STAT_SEM,运行OS_EventTO,做的事刚好和OS_EventTaskWait相反。
    (1)OSTCBCur->OSTCBEventPtr = 0;
    (2)设置任务控制块中的状态标志为就绪状态(去除OS_STAT_SEM状态)
    (3)去除事件控制块中的任务等待表

    此时返回OS_TIMEOUT。
    但是如果在等待时间未过去,其他任务释放了信号量,OSSemPost能够在释放信号量的同时,恢复等待信号量的任务。等待信号量的任务恢复运行,此时任务控制块的状态标志不包含OS_STAT_SEM了,所以函数直接跳过第二个if语句,返回OS_NO_ERR。
释放信号量过程:
    函数OSSemPost在对信号量的计数器操作之前,首先检查任务等待表中是否还有其他等待该信号的任务,如果没有,就把计数器加1,如果有,则调用OS_EventTaskRdy将任务等待表中最高优先级的任务设为就绪状态,并调用OSSched调度任务。
 
3. 应用
3.1申请函数和释放函数在同一任务中成对出现
main:
pevent = OSSemCreate(1);
task1:
OSSemPend(pevent, 0, err);
....
OSSemPost(pevent);
task2:
OSSemPend(pevent, 0, err);
....
OSSemPost(pevent);

当一个任务没有释放信号量,另一个任务在申请信号量时只能挂起直到信号量释放。
3.2 应用程序中有一个函数Fun(),如果想使任务M必须经过Y任务允许才能调用函数一次,可以使用信号量
main:
pevent = OSSemCreate(0);
task1:
OSSemPend(pevent, 0, err);
Fun();
task2:
OSSemPost(pevent);
本文链接:http://www.cnblogs.com/cposture/p/4299055.html

转载于:https://www.cnblogs.com/cposture/p/4299055.html

【原创】ucos信号量的操作及原理相关推荐

  1. 嵌入式操作系统内核原理和开发(信号量)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 之前因为工作的原因,操作系统这块一直没有继续写下去.一方面是自己没有这方面的经历,另外一方面就 ...

  2. 嵌入式操作系统内核原理和开发

    嵌入式操作系统内核原理和开发(开篇) 操作系统是很多人每天必须打交道的东西,因为在你打开电脑的一刹那,随着bios自检结束,你的windows系统已经开始运行了.如果问大家操作系统是什么?可能有的人会 ...

  3. linux优先级继承和优先级天花板,关于Linux操作系统内核原理.ppt

    <铁机>Linux操作系统内核原理 Linux内核基础 第一事业部 王 风 内容 进程管理 内存管理 虚拟文件系统 了解Linux内核核心功能的基本原理结构,引导源码阅读 Linux系统结 ...

  4. 嵌入式操作系统内核原理和开发(总结篇)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 很多朋友都喜欢嵌入式操作系统的内容,但是如何实现和仿真这样一个系统一直是困扰我们的难题.现在郑 ...

  5. 【原创】反调试技巧总结-原理和实现(1)(2)(3)(4)(5)(6)......

    标 题: [原创]反调试技巧总结-原理和实现(1)(2)(3)(4)(5)(6)...... 作 者: shellwolf 时 间: 2008-08-10,22:40:53 链 接: http://b ...

  6. 8 操作系统第二章 进程管理 信号量 PV操作 用信号量机制实现 进程互斥、同 步、前驱关系

    文章目录 1 信号量机制 1.1 整形信号量 1.2 记录形信号量 1.3 信号量机制小结 2 用信号量机制实现进程互斥.同 步.前驱关系 2.1 信号量机制实现进程互斥 2.2 信号量机制实现进程同 ...

  7. 封装一个信号量集操作函数的工具

    信号量的概念参见这里. 与消息队列和共享内存一样,信号量集也有自己的数据结构: struct semid_ds { struct ipc_perm sem_perm;  /* Ownership an ...

  8. linux pv 信号量,pv操作与信号量(示例代码)

    在python同步编程部分,需要分析和思考多个线程之间同步互斥问题,因此pv操作和信号量作为基础和重中之重,特此回顾pv操作和信号量. PV操作由P操作原语和V操作原语组成(原语即不可在分割的操作), ...

  9. 关于Linux中的apt-get的相关操作及原理

    关于Linux中的apt-get的相关操作及原理 Linux下的apt-get指令与相关文件夹 apt-get是linux下的一种简便的安装和更新软件的方法,在装软件的时候常用的命令就是 sudo a ...

最新文章

  1. dlib的编译和安装
  2. AngularJs前端环境搭建
  3. 分享GitHub上一位老外的嵌入式C编码规范(收藏细读)
  4. iOS中GCD的魔力
  5. hibernate 复合主键 根据主键删除_6道常见的 Hibernate 面试题
  6. Bound Found POJ - 2566 (尺取+前缀和)
  7. BurpSuit配置抓包http和https请求
  8. IdentityServer4专题之二:OpenID介绍
  9. Python中添加中文注释报错SyntaxError: Non-UTF-8 code starting with '\xc1'
  10. Luogu1502 窗口的星星
  11. 抖音快手无水印视频下载教程解析
  12. 快递行业面单打印解决方案-快宝云打印
  13. java多种货币的相互转换_使用java将不同的国家货币转换为双倍
  14. 声学模型GMM-HMM训练
  15. Websocket(二)-客户端与服务器通信
  16. 计算机上用户名怎么设置,电脑用户名,详细教您电脑用户名怎么修改
  17. Chrome 插件(Shockwave Flash)未响应 错误解决办法
  18. N1盒子Armbian折腾记
  19. 给input date设置默认值
  20. ReactiveX/RxJava V3.0.0版本

热门文章

  1. nmon工具的安装记录
  2. C#获取当前系统磁盘符、系统目录、桌面等
  3. jQuery 学习笔记(jQuery: The Return Flight)
  4. 台式机共享笔记本的无线网络(只需要一根网线)
  5. asp.net mvc使用TagBuilder的应用程序集
  6. fluorinefx C# 版的开源rtmp服务器
  7. php bloginfo stylesheeturl,WordPress主题制作–bloginfo函数使用教程
  8. linux3.4.2移植总结(s3c2440)
  9. linux查看数据积压,查看kafka消息队列的积压情况
  10. 2清空所有表_拉链表(二)