1 信号量概念
在vxworks中使用信号量工具对互斥与任务同步进行操作。在wind内核中存在二进制信号量、互斥信号量及计
数信号量。互斥:当共享地址空间进行简单的数据交换时,为避免竞争需要对内存进行互锁,即多个任务访问共享内存时,体现出来的排它性。使用二进制信号量就可以很方便地实现互斥,当多个任务访问共享资源时,对该资源设置一个信号量(相当于令牌),那么拿到该令牌的任务就可以独享该资源。
2 二进制信号量互斥实现说明与代码模型参考
二进制信号量需要的系统开销最小,因而特别适合于高性能的需求。
注意:
(1)互斥中的信号量与任务优先级的关系:任务的调度还是按照任务优先级进行,但是在使用内存的时候只有一个任务获得信号量,也就是说还是按照任务优先级获得信号量从而访问资源。只有当前使用资源的任务使用semGive()释放信号量后,其它任务按照优先级才可以获得信号量。
(2)信号量属性中的参数为:SEM_Q_PRIORITY。而且在创建信号量的时候必须把信号量置为满SEM_FULL,即信号量可用,等待信号的任务可以根据优先级顺序(SEM_Q_PRIORITY)或者先进先出(SEM_Q_FIFO)进行排队。
如图1所示,使用semBCreate(),分配并初始化一个二进制信号量,返回值为一信号量ID,为其他信号量控制函数的应用提供句柄,并设置资源可用(full)还是不可(empty)。
任务可以调用semTake()函数提取二进制信号量,如果信号量可用(full)那么将变得不可用(empty),同时任务继续执行。如果信号量不可用(empty),调用semTake()函数的任务将被放到一个阻塞队列中,处于等待信号量可用的状态(pending挂起)。
semGive()可用于释放信号量。若信号量不可用(empty)并且没有任务在等待它,那么该信号量将变得可用(full),若信号量不可用(empty)并且有任务在等待它,那么 阻塞队列中的第一个任务将得到该信号量变得不阻塞, 同时 该信号量仍旧不可用(empty),若信号量可用(full),调用semGive()不产生任何影响。
互斥模型程序说明:
<span style="color:#FFCCCC;"><span style="color:#330033;">SEM_ID semMutex; semMutex = semBCreate(SEM_Q_PRIORITY, SEM_FULL);//优先级顺序排队,信号量可用 task(void) { semTake(semMutex, WAIT_FOREVER);//得到信号量,即相当于得到使用资源的令牌 //临界区,某一个时刻只能由一个任务访问 semGive(semMutex); }</span></span>
3 二进制信号量任务同步实现
任务同步:任务利用信号量控制自己的运行进度,按照一定的先后顺序执行。例如为了任务A与B同步,A与B可以共享一个信号量,初始值设置为不可用,在A之后调用semGive在B之前调用semTakeSEM_ID 即可。
SEM_ID semSync;
semSync = semBCreate(SEM_Q_FIFO, SEM_EMPTY); taskA(void) { semGive(semSync); //信号量释 }taskB(void){ semTake(semSync, WAIT_FOREVER); //获取信号量}
注意:
(1)创建的新的信号量初始值应当为不可用(empty),因而可能使得优先级翻转,即高优先级任务在低优先级任务之后执行;
(2)属性参数设置:SEM_Q_FIFO,SEM_EMPTY。在不同的TASK中分别单独调用semTake(),semGive()且先后顺序不能颠倒。
(3)禁止删除那些任务正在请求信号量。
(4)semTake()不可以在中断中调用,因为调用semTake()的函数可能被挂起,而中断不可以被挂起。semGive()可以在中断中调用
例子程序:
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("task t_imaGet get the semaphore\n "); semGive(semFs); //释放信号量 } void t_imaJud(void) { semTake(semFs, WAIT_FOREVER);//确保优先级不反转 printf("task imaJud get the semaphore\n"); semGive(semFss); } void t_imaPro(void) { semTake(semFss, WAIT_FOREVER); printf("task imaProget the semaphore\n"); semGive(semFex); } void t_imaExc(void) { semTake(semFex, WAIT_FOREVER); printf("task imaExcthe semaphore\n"); } 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); }