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()不產生任何影響。
圖1
互斥模型程序說明:
<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); }