Wind内核中有二进制信号量、计数信号量和互斥信号量三种类型,为了使应用程序具有可移植性,还提供了POSIX(可移植操作系统接口)信号量。 在Vxorks操作系统中,信号量是实现任务同步的主要手段,也是解决任务同步问题的最佳选择。 关于互斥的实现: 使用互斥信号量可以很方便的实现互斥,互斥是指多任务在访问临界资源时具有排他性。为使多个任务互斥访问临界资源,只需要为该资源设置一个信号量,相当于一个令牌,哪个任务拿到这个令牌即有权使用该资源。把信号量设为可用,然后将需要资源的任务的临界代码置于semTake()和SemGive()之间即可。 注明: 1. 互斥中的信号量与任务优先级的关系:任务的调度还是按照任务优先级进行,但是在使用临界资源的时候只有一个任务获得信号量,也就是说还是按照任务优先级来获得信号量从而访问资源。只有当前使用资源的任务释放信号量SemGive(),其他任务按照优先级获得信号量。 2. 信号量属性中的参数为:SEM_Q_PRIORITY。而且在创建信号量的时候必须把信号量置为满的SEM_FULL。即信号量可用。 关于semTake() 函数: 任务使用 semTake()取一个信号量,其结果取决于调用时该二进制信号量是否可用。如果可用,信号量将变得不可用,而任务继续执行。如果信号量不可用,任务被挂起到任务阻塞队列,直到该信号量可用。 关于semGive()函数: 当任务释放一个互斥信号量时要调用 semGive(),其结果也要依赖于调用时刻该信号量是否可用。如果可用,本次释放信号量不起任何作用;如果信号量不可用,而且没有任务在等待该信号量,那么信号量变为可用;如果信号量不可用,并且有一个或多个任务等待该信号量,那么阻塞队列中的第一个任务解除阻塞,而信号量仍不可用。 基本实现互斥模型: SEM_ID semMutex; semMutex = semBCreate(SEM_Q_PRIORITY, SEM_FULL); task(void) { semTake(semMutex,WAIT_FOREVER);//得到信号量,即相当于得到使用资源的令牌 //临界区,某一个时刻只能由一个任务访问; semGive(semMutex); } 互斥信号量与二进制信号量的比较: 互斥信号量可以看作一种特殊的二进制信号量,其支持普通二进制信号量不支持的一些特性,提供优先级继承、安全删除和回归能力。互斥信号量的使用方法和二进制信号量基本类似,但有如下区别: (1)仅仅被用做互斥,不能提供同步机制; (2)只能被使用它的任务释放; (3)中断服务程序(ISR)不能释放它; (4)不能使用函数semFlush( ); (5)支持使用二进制信号量进行互斥时所不支持的优先级“翻转”。 关于任务同步的实现: 同步即任务按照一定顺序先后执行,为了实现任务A和B的同步,只需要让任务A和B共享一个信号量,并设初始值为空,即不可用,将semGive()置于任务A之后,而在任务B之前插入semTake()即可. 说明: 1. 还是讨论和优先级的关系。由于信号量初始化为空,不可用,所以可能使得优先级反转,即高优先级任务B在等待低优先级任务A释放信号量。只有执行了信号量释放语句semGive()后任务B得到信号量才能执行。 2. 属性参数的设置为SEM_Q_FIFO,SEM_EMPTY; 实现模式参考: SEM_ID semSync; semSync = semBCreate(SEM_Q_FIFO,SEM_EMPTY); taskA(void) { ………. semGive(semSync); //信号量释放,有效。 } taskB(void) { semTake(semSync,WAIT_FOREVER); //等待信号量。 …….. } 使用信号量注意事项: 1. 用途不同,信号量属性和初始值不同; 2. 互斥访问资源使,semTake()和semGive()必须成对出现,且先后顺序不能颠倒; 3. 避免删除那些其他任务正在请求的信号量。 应用: 1、 确保任务优先级不反转: SEM_ID semFs; SEM_ID semFss; SEM_ID semFex; semFs = semBCreate (SEM_Q_FIFO , SEM_EMPTY); semFss = semBCreate (SEM_Q_FIFO , SEM_EMPTY); semFex = semBCreate (SEM_Q_FIFO , SEM_EMPTY); //创建三个信号量 void t_imaGet(void) { printf("a "; semGive(semFs); //释放信号量 } void t_imaJud(void) { semTake(semFs,WAIT_FOREVER); //确保优先级不反转。 printf("jj "; semGive(semFss); } void t_imaPro(void) { semTake(semFss,WAIT_FOREVER); printf("rr"; semGive(semFex); } void t_imaExc(void) { semTake(semFex,WAIT_FOREVER); printf("Y"; } void start(void) { int tGetId,tJudId,tProId,tExcId; tGetId = taskSpawn("tPget",200,0,1000,(FUNCPTR)t_imaGet,1,0,0,0,0,0,0,0,0,0); tJudId = taskSpawn("tPjud",201,0,1000,(FUNCPTR)t_imaJud,3,0,0,0,0,0,0,0,0,0); tProId = taskSpawn("tPpro",202,0,1000,(FUNCPTR)t_imaPro,3,0,0,0,0,0,0,0,0,0); tExcId = taskSpawn("tPexc",203,0,1000,(FUNCPTR)t_imaExc,3,0,0,0,0,0,0,0,0,0); } 以上例子虽然定了各个任务的优先级,但加上信号量可以实现同步,而且防止优先级反转出现。 |