UCOSIII操作系统——信号量与互斥量篇(1)信号量

UCOSIII其他内容导航不迷路
UCOSIII操作系统-简介
UCOSIII操作系统——任务篇(1)创建任务
UCOSIII操作系统——任务篇(2)相关API函数
UCOSIII操作系统——系统初始化篇(1)系统初始化
UCOSIII操作系统——系统初始化篇(2)CPU,SysTick,内存初始化
UCOSIII操作系统——硬件初始化篇(1)硬件初始化以及开始运行系统
正在更新整理…

说在前面:
这个内容不适合0基础的人,因为这里只讲了应用层面的东西,并没有深入内核讲解,所以要从零开始学UCOSIII的朋友,可以先去学完入门内容,再来观看这个笔记加深印象。
这篇文章是个人学习整理,如有错误请指正

UCOSIII操作系统——信号量与互斥量篇(1)信号量

信号量(Semaphore)是一种实现任务间通信的机制,可以实现任务之间同步或临界资源的互斥访问,常用于协助一组相互竞争的任务来访问临界资源。在多任务系统中,各任务之间需要同步或互斥实现临界资源的保护,信号量功能可以为用户提供这方面的支持。
信号量像是一种上锁机制,代码必须获得对应的钥匙才能继续执行,一旦获得了 钥匙,也就意味着该任务具有进入被锁部分代码的权限。一旦执行至被锁代码段,则任务一直等待,直到对应被锁部分代码的钥匙被再次释放才能继续执行。

二进制信号量

某一资源对应的信号量为1的时候,那么就可以使用这一资源,如果对应资源的信号量为0,那么等待该信号量的任务就会被放进等待信号量的任务表中。在等待信号量的时候也可以设置超时,如果超过设定的时间任务没有等到信号量的话那么该任务就会进入就绪态。任务以“发信号”的方式操作信号量。可以看出如果一个信号量为二进制信号量的话,一次只能-一个任务:使用共享资源。

计数型信号量

有时候我们需要可以同时有多个任务访问共享资源,这个时候二进制信号量就不能使用了,计数型信号量就是用来解决这个问题的。比如某—个信号量初始化值为10,那么只有前10个请求该信号量的任务可以使用共享资源,以后的任务需要等待前10个任务释放掉信号量。每当有任务请求信号量的时候,信号量的值就会减1,直到减为0。当有任务释放掉信号量的时候信号量的值就会加1。

信号量的API函数

函数 描述
OSSemCreate() 创建一个信号量(常用)
OSSemDel() 删除一个信号量
OSSemPend() 等待一个信号量(常用)
OSSemPendAbort() 取消等待
OSSemPost() 释放一个信号量(常用)
OSSemSet() 强制设置一个信号量的值

创建信号量->OSSemCreate()

void  OSSemCreate (OS_SEM      *p_sem,		//信号量控制块指针
                   CPU_CHAR    *p_name,		//信号量名称
                   OS_SEM_CTR   cnt,		//资源数目或事件是否发生标志
                   OS_ERR      *p_err)		//返回错误类型

信号量控制块指针: 指向我们定义的信号量控制块结构体变量, 所以在创建之前我们需要先定义一个信号量控制块变量。

OS_SEM	MY_SEM;		//定义一个信号量

cnt: 这个值表示初始化时候资源的个数或事件是否发生标志,一般信号量是二值信号量的时候,这个值一般为0或者为1,而如果信号量作为计数信号量的时候,这个值一般定义为初始资源的个数。

删除信号量-> OSSemDel()

OSSemDel0用于删除一个信 号量,信号量删除函数是根据信号量结构(信号量句柄)直接删除的,删除之后这个信号量的所有信息都会被系统清空,而且不能再次使用这个信号量了,但是需要注意的是,如果某个信号量没有被定义,那也是无法被删除的,如果有任务阻塞在该信号量上,那么尽量不要删除该信号量。想要使用互斥量删除函数就必须将OS_ CFG_ SEM_ DEL_ EN宏定义配置为1。

  • 函数原型
#if OS_CFG_SEM_DEL_EN > 0u				//如果使能了 OSSemDel() 函数
OS_OBJ_QTY  OSSemDel (OS_SEM  *p_sem,	//信号量指针
                      OS_OPT   opt,		//选项
                      OS_ERR  *p_err)	//返回错误类型
  • 选项opt
OS_OPT_DEL_NO_PEND: //如果只在没有任务等待的情况下删除信号量
OS_OPT_DEL_ALWAYS: //无论如何必须删除信号量

释放一个信号量->OSSemPost()

任务获得信号量以后就可以访问共享资源了,在任务访问完共享资源以后必须释放信号量,释放信号量也叫发送信号量,使用函数OSSemPost()发送信号量。如果没有任务在等待该信号量的话则OSSemPost()函数只是简单的将信号量加1,然后返回到调用该函数的任务中继续运行。如果有一个或者多个任务在等待这个信号量,则优先级最高的任务将获得这个信号量,然后由调度器来判定刚获得信号量的任务是否为系统中优先级最高的就绪任务,如果是,则系统将进.行任务切换,运行这个就绪任务。

  • 函数原型
OS_SEM_CTR  OSSemPost (OS_SEM  *p_sem,		//信号量控制块指针
                       OS_OPT   opt,		//选项
                       OS_ERR  *p_err)		//返回错误类型
  • 选项opt
OS_ OPT_ POST_ 1			仅向等待该信号量的优先级最高的任务发送信号量。
OS_ OPT _POST_ ALL			向等待该信号量的所有任务发送信号量。
OS_ OPT_ POST_ NO SCHED		该选项禁止在本函数内执行任务调度操作。即使该函数使得更高优先级的任务结束挂起进入就绪状态,也不会执行任务调度,而是会在其他后续函数中完成任务调度。
  • 应用实例
OS_SEM SemOfKey; //标志KEY1 是否被按下的信号量
OSSemPost((OS_SEM *)&SemOfKey, //发布SemOfKey
		(OS_OPT )OS_OPT_POST_ALL, //发布给所有等待任务
		(OS_ERR *)&err); //返回错误类型

等待一个信号量->OSSemPend()

与消息队列的操作一样,信号量的获取可以在任务中使用。
与释放信号量对应的是获取信号量,我们知道,当信号量有效的时候,任务才能获取信号量,当任务获取了某个信号量的时候,该信号量的可用个数就减一-,当它减到0的时候,任务就无法再获取了,并且获取的任务会进入阻塞态(假如用户指定了阻塞超时时间的话)。如果某个信号量中当前拥有1个可用的信号量的话,被获取一次就变得无效了,那么此时另外一个任务获取该信号量的时候,就会无法获取成功,该任务便会进入阻塞态,阻塞时间由用户指定。
uCOS支持系统中多个任务获取同一个信号量,假如信号量中已有多个任务在等待,那么这些任务会按照优先级顺序进行排列,如果信号量在释放的时候选择只释放给一个任务,那么在所有等待任务中最高优先级的任务优先获得信号量,而如果信号量在释放的时候选择释放给所有任务,则所有等待的任务都会获取到信号量。

  • 函数原型
OS_SEM_CTR  OSSemPend (OS_SEM   *p_sem,		//信号量指针
                       OS_TICK   timeout,	//等待超时时间
                       OS_OPT    opt,		//选项
                       CPU_TS   *p_ts,		//等到信号量时的时间戳
                       OS_ERR   *p_err)		//返回错误类型
  • 选项opt
    用于设置是否使用阻塞模式,有下面两个选项。
    OS_OPT_PEND_BLOCKING 指定信号量无效时,任务挂起以等待信号量。
    OS_ OPT_ PEND_ NON_ BLOCKING 信号量无效时,任务直接返回。
  • 应用实例
OSSemPend ((OS_SEM *)&SemOfKey, 			//等待该信号量被发布
			(OS_TICK )0, 					//无期限等待
			(OS_OPT )OS_OPT_PEND_BLOCKING,	//如果没有信号量可用就等待
			(CPU_TS *)&ts_sem_post, 		//获取信号量最后一次被发布的时间戳
			(OS_ERR *)&err);				//返回错误类型

详细代码可以参考正点原子
例10-2 UCOSIII使用信号量访问共享资源区
例10-3 UCOSIII使用信号量进行任务同步

发布了10 篇原创文章 · 获赞 1 · 访问量 119

猜你喜欢

转载自blog.csdn.net/iiinoname/article/details/105194834