vxworks系統學習----二進制信號量

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);
}








發佈了28 篇原創文章 · 獲贊 19 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章