例子一: 这个例子中,两个任务(taskOne 和 taskTwo)竞争修改一个全局变量 global 的值,任务 taskOne 将 Global修改为1,而任务taskTwo 则将其修改为 0。 #define ITER 10 SEM_ID semBinary; int global = 0; static void taskOne(void) { int i; for(i=0;i<ITER;i++) { semTake(semBinary,WAIT_FOREVER); printf("I am taskOne and global = %d...............\n",++global); semGive(semBinary); } } static void taskTwo(void) { int i; semGive(semBinary); /*Note1:must release the semBinary occupied by s3_sem before the s3_sem ends*/ for(i=0;i<ITER;i++) { semTake(semBinary,WAIT_FOREVER); printf("I am taskTwo and global = %d...............\n",--global); semGive(semBinary); } } void s3_sem(void) { int taskIdOne,taskIdTwo; semBinary = semBCreate(SEM_Q_FIFO,SEM_FULL); semTake(semBinary,WAIT_FOREVER); /*Note2*/ taskIdOne = taskSpawn("t1",90,0x100,2000,(FUNCPTR)taskOne,0,0,0,0,0,0,0,0,0,0); taskIdTwo = taskSpawn("t2",90,0x100,2000,(FUNCPTR)taskTwo,0,0,0,0,0,0,0,0,0,0); logMsg("s3_sem:s3_sem ends.\n",0,0,0,0,0,0); /*at the end of function s3_sem, two tasks were created and CPU resource was gave back to the OS */ } taskOne 和taskTwo 优先级一样,如果没有 Note1和Note2,taskOne将首先执行完,然后taskTwo再执行完,在s3_sem中taskSpawn使得taskOne,taskTwo就绪,但是优先级一致,所以按照创建的顺序依次执行。 为了让taskOne和taskTwo互相争夺资源global变量,先由s3_sem占据信号量,阻塞taskOne使其进入等待状态,然后taskTwo就绪后运行时先释放信号量然后被阻塞,taskOne执行一次++global,再释放信号量,taskTwo然后执行一次--global. 关键是要让taskOne和taskTwo进入阻塞队列,这样信号量才会对优先级一致的任务起到作用。 例子二: 当高优先级的任务不得不等待一段不确定的时间,等待低优先级任务完成操作时,就发生优先级倒转。例如,prioHigh、prioMedium和prioLow三个任务的优先级由高到低排列,prioLow 请求一个与二进制信号量相联系的资源,当prioHigh 抢占prioLow并需要竞争相同的资源,它将被阻塞。如果 prioHigh 阻塞 的时间全部用来等待prioLow使用该资源,那么不会存在什么问题,因为资源不会被抢占。然而,如果这个低优先级的任务不得不被中等优先级的任务prioMedium 抢占,由于它不需要使用该资源,这时 prioLow 仍然占用该资源。这种情况可能进一步发生,使得 prioHigh 被迫等待一段不确定的时间。 <fertiland:优先级反转, 系统task调度与信号量机制发生冲突出现的问题.> 为避免这种情况,VxWorks 引进优先级继承机制。 为使用优先级继承机制,当使用互斥信号量时,VxWorks 提供了一个附加的选项 SEM_INVERSION_SAFE,它允许使用优先级继承算法,该算法保证占有一个资源的任务,在其运行时,其优先级等于阻塞在该资源上的所有任务的优先级的最高值。当执行完成,这个任务释放资源,返回正常的优先级。因此,这个继承了最高优先级的任务, 将不会被优先级比它的正常优先级高但又比继承的优先级低的任务抢占。 需要指出的是SEM_INVERSION_SAFE选项必须与SEM_Q_PRIORITY一起使用: semId = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE) ; 下面的例子说明发生优先级倒转的典型情况: (1) prioLow任务上锁信号量; (2) prioLow 任务被 prioMedium 任务抢占而阻塞,后者运行一段较长的时间; (3) prioHigh 任务抢占 prioMedium 任务,试图上锁被 prioLow 上锁的信号量。 #include "vxWorks.h" #include "taskLib.h" #include "kernelLib.h" #include "semLib.h" #include "sysLib.h" #define ITER 3 #define LONG_TIME (1<<25) #define HIGH 102 #define MID 103 #define LOW 104 SEM_ID semMutex; static void prioLow(void) { int i,j; for(i=0;i<ITER*2;i++) { semTake(semMutex,WAIT_FOREVER); logMsg("Low priority task locked semaphore\n",0,0,0,0,0,0); for(j=0;j<LONG_TIME;j++); logMsg("Low priority task unlocked semaphore\n",0,0,0,0,0,0); semGive(semMutex); } logMsg("-----------------------------Low priority task exited.\n",0,0,0,0,0,0); } static void prioMedium(void) { int i; taskDelay(2); //task prioMedium ocuppy prioLow after 20 ticks for(i=0;i<LONG_TIME*10;i++) { if((i%LONG_TIME)==0) logMsg("Medium task running.\n",0,0,0,0,0,0); } logMsg("-----------------------------Medium priority task exited.\n",0,0,0,0,0,0); } static void prioHigh(void) { int i,j; taskDelay(20); for(i=0;i<ITER;i++) { logMsg("High priority task trys to lock semaphore.\n",0,0,0,0,0,0); semTake(semMutex,WAIT_FOREVER); logMsg("High priority task locked semaphore.\n",0,0,0,0,0,0); for(j=0;j<LONG_TIME;j++); logMsg("High priority task unlocked semaphore.\n",0,0,0,0,0,0); semGive(semMutex); } logMsg("-----------------------------High priority task exited.\n",0,0,0,0,0,0); } void s7_inversion(void) { int i,low,medium,high; logMsg("\n\n..............##s7_inversion RUNNING##...............\n\n\n",0,0,0,0,0,0); semMutex = semMCreate(SEM_Q_PRIORITY); if((low=taskSpawn("task1",LOW,0x100,20000, (FUNCPTR)prioLow,0,0,0,0,0,0,0,0,0,0))==ERROR) logMsg("taskSpawn task1 prioLow failed.\n",0,0,0,0,0,0); if((medium=taskSpawn("task2",MID,0x100,20000, (FUNCPTR)prioMedium,0,0,0,0,0,0,0,0,0,0))==ERROR) logMsg("taskSpawn task2 proMeidum failed.\n",0,0,0,0,0,0); if((high=taskSpawn("task3",HIGH,0x100,20000, (FUNCPTR)prioHigh,0,0,0,0,0,0,0,0,0,0))==ERROR) logMsg("taskSpawn task3 prioHigh failed.\n",0,0,0,0,0,0); } VxSim 的输出: ..............##s7_inversion RUNNING##............... 0x1c76598 (task1): Low priority task locked semaphore 0x1c6e420 (task2): Medium task running. -----------> Medium 抢占资源,阻塞 Low 0x1c6e420 (task2): Medium task running. -----------> 信号量被抢占,High也被阻塞 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c662a8 (task3): High priority task trys to lock semaphore. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): -----------------------------Medium priority task exited. 0x1c76598 (task1): Low priority task unlocked semaphore --------> Medium执行完,Low才有机 0x1c662a8 (task3): High priority task locked semaphore. -------->会释放信号量 0x1c662a8 (task3): High priority task unlocked semaphore. 0x1c662a8 (task3): High priority task trys to lock semaphore. 0x1c662a8 (task3): High priority task locked semaphore. 0x1c662a8 (task3): High priority task unlocked semaphore. 0x1c662a8 (task3): High priority task trys to lock semaphore. 0x1c662a8 (task3): High priority task locked semaphore. 0x1c662a8 (task3): High priority task unlocked semaphore. 0x1c662a8 (task3): -----------------------------High priority task exited. 0x1c76598 (task1): Low priority task locked semaphore 0x1c76598 (task1): Low priority task unlocked semaphore 0x1c76598 (task1): Low priority task locked semaphore 0x1c76598 (task1): Low priority task unlocked semaphore 0x1c76598 (task1): Low priority task locked semaphore 0x1c76598 (task1): Low priority task unlocked semaphore 0x1c76598 (task1): Low priority task locked semaphore 0x1c76598 (task1): Low priority task unlocked semaphore 0x1c76598 (task1): Low priority task locked semaphore 0x1c76598 (task1): Low priority task unlocked semaphore 0x1c76598 (task1): -----------------------------Low priority task exited. 引入优先级继承机制:semMutex = semMCreate(SEM_Q_PRIORITY|SEM_INVERSION_SAFE); ..............##s7_inversion RUNNING##............... 0x1c76598 (task1): Low priority task locked semaphore 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c662a8 (task3): High priority task trys to lock semaphore. -------->High 可以阻塞Medium, 可以使Low 0x1c76598 (task1): Low priority task unlocked semaphore --------->释放信号量 0x1c662a8 (task3): High priority task locked semaphore. 0x1c662a8 (task3): High priority task unlocked semaphore. 0x1c662a8 (task3): High priority task trys to lock semaphore. 0x1c662a8 (task3): High priority task locked semaphore. 0x1c662a8 (task3): High priority task unlocked semaphore. 0x1c662a8 (task3): High priority task trys to lock semaphore. 0x1c662a8 (task3): High priority task locked semaphore. 0x1c662a8 (task3): High priority task unlocked semaphore. 0x1c662a8 (task3): -----------------------------High priority task exited. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): Medium task running. 0x1c6e420 (task2): -----------------------------Medium priority task exited. 0x1c76598 (task1): Low priority task locked semaphore 0x1c76598 (task1): Low priority task unlocked semaphore 0x1c76598 (task1): Low priority task locked semaphore 0x1c76598 (task1): Low priority task unlocked semaphore 0x1c76598 (task1): Low priority task locked semaphore 0x1c76598 (task1): Low priority task unlocked semaphore 0x1c76598 (task1): Low priority task locked semaphore 0x1c76598 (task1): Low priority task unlocked semaphore 0x1c76598 (task1): Low priority task locked semaphore 0x1c76598 (task1): Low priority task unlocked semaphore 0x1c76598 (task1): -----------------------------Low priority task exited. |