信號量
除了臨界點機制、互斥量機制可實現(xiàn)臨界資源的互斥訪問外,信號量(Semaphore)是另一選擇。
信號量與互斥量的區(qū)別
- 對于互斥量來說,主要應用于臨界資源的互斥訪問,并且能夠有效地避免優(yōu)先級反轉問題。
- 對于信號量而言,它雖然也能用于臨界資源的互斥訪問,但是不能處理優(yōu)先級反轉問題。
也正因為信號量沒有考慮優(yōu)先級反轉問題,所以相對于互斥量來說是一種輕量級的實現(xiàn)方式,比互斥量耗費更少的CPU資源。
此外,信號量除了用于互斥,還可以用于處理不同線程之間的同步問題,而互斥量卻不行。
針對上述情況,有三種類型的信號量,按照功能來分,可以分為線程對臨界資源互斥訪問的互斥信號量、用于線程間同步的信號量、控制系統(tǒng)中臨界資源的多個實例使用的計數(shù)信號量。
用于同步的信號量其初始值在創(chuàng)建信號量時設置為0,表示同步事件尚未發(fā)生。
臨界資源互斥的信號量初始值為1,表明當前沒有任務獲取該信號量。
用于控制系統(tǒng)中臨界資源的多個實例使用的計數(shù)信號量其初始值為n,表明需要管理的實例個數(shù)最大數(shù)為n,這樣的信號量也稱為計數(shù)信號量。
以下例子,通過一個計數(shù)信號量和互斥信號量實現(xiàn)對一個有界緩沖使用的控制,這就是“生產者與消費者”問題。
- 計數(shù)信號量FULL表示已經被填充了的數(shù)據(jù)項目。
- 計數(shù)信號量EMPTY表示空閑數(shù)據(jù)項數(shù)目。
以上的取值范圍均為(0,n-1),其初始值分別為0,n-1。
由于有界緩沖區(qū)是共享資源,還需要一個互斥信號量MUTEX控制生產者線程與消費者線程對它的互斥訪問,其初始值為1。
創(chuàng)建信號量
acoral_evt_t *acoral_sem_create(unsigned int semNum)
{
acoral_evt_t *evt;
evt = acoral_alloc_evt();
if (NULL == evt)
{
return NULL;
}
semNum = 1 - semNum;
evt->count = semNum;
evt->type = ACORAL_EVENT_SEM;
evt->data = NULL;
acoral_evt_init(evt);
return evt;
}
初始化信號量。當靜態(tài)定義信號量而不是采用指針形式定義時,內存空間已經在定義時分配,此時應當調用初始化函數(shù)acoral_sem_init()對定義過的信號量進行初始化。
aCoralSemRetValEnum acoral_sem_init(acoral_evt_t *evt,unsigned int semNum)
{
if(NULL == evt)
{
return SEM_ERR_NULL;
}
semNum = 1 - semNum;
evt->count = semNum;
evt->type = ACORAL_EVENT_SEM;
evt->data = NULL;
acoral_evt_init(evt);
return SEM_SUCCED;
}
與互斥量初始化類似,就是為acoral_evt_t各個成員賦值。
這里需要提及的是count初始化,從傳入的參數(shù)semNum可知,該變量用來表示當前信號量所控制的臨界資源的實例的數(shù)量,但在具體實現(xiàn)時,并不是和大家想象的數(shù)字一樣,如1代表有1個資源,2代表有2個資源…
在實現(xiàn)時,實例數(shù)量是用“1-semNum”來表示的,此時0代表有1個資源,-1代表有兩個資源,1代表已經沒有資源,且有1個線程在等待該資源實例。
申請信號量。申請信號量時需要傳入兩個參數(shù):先前創(chuàng)建的信號量的地址,超時處理的時間。
acoralSemRetValEnum acoral_sem_pend(acoral_evt_t *evt, unsigned int timeout)
{
acoral_thread_t *cur = acoral_cur_thread;
if(acoral_intr_nesting)
{
return SEM_ERR_INTR;
}
if(NULL == evt)
{
return SEM_ERR_NULL;
}
if(ACORAL_EVENT_SEM != evt->type)
{
return SEM_ERR_TYPE;
}
//計算信號量處理
acoral_enter_critical();
/*判斷是否還有可用資源,從前面的介紹可知,這里的SEM_RES_AVAI其實就是0,如果count數(shù)目小于等于0,代表有資源實例。如果count大于0,代表在等待的有多少個線程。如果有可用的資源實例,讓count的數(shù)目加一后退出,表示成功申請信號量。*/
if((char)evt->count <= SEM_RES_AVAI)
{
evt->count++;
acoral_exit_critical();
return SEM_SUCCED;
}
//如果無可用的資源實例,讓count的數(shù)目加一后,再將自身掛起,重新調度線程
evt->count++;
acoral_unrdy_thread(cur);
if(timeout > 0)
{
cur->delay = TIME_TO_TICKS(timeout);
timeout_queue_add(cur);
}
acoral_evt_queue_add(evt, cur);
acoral_exit_critical();
acoral_sched();
acoral_enter_critical();
//如果某個線程等待某個資源實例而又無法獲取,它將被掛起,而若它希望被掛起的時間小于一個設定值timeout,還需將TCB的成員更新為timeout,并掛載到延遲隊列中,如果延遲時間到,將進行相應處理
if(timeout > 0 && cur->Delay <= 0)
{
evt->count--;
acoral_evt_queue_Del(cur);
acoral_exit_critical();
return SEM_ERR_TIMEOUT;
}
timeout_queue_del(cur);
acoral_exit_critical();
return SEM_SUCCED;
}
釋放信號量
acoralSemRetValEnum acoral_sem_post(acoral_evt_t *evt)
{
acoral_thread_t *thread;
/* 參數(shù)檢測*/
if (NULL == evt)
{
return SEM_ERR_NULL; /* error*/
}
if (ACORAL_EVENT_SEM != evt->type)
{
return SEM_ERR_TYPE;
}
acoral_enter_critical();
if((char)evt->count <= SEM_RES_NOVAI)
{
evt->count--;
acoral_exit_critical();
return SEM_SUCCED;
}
evt->count--;
thread = acoral_evt_high_thread(evt);
if(thread == NULL)
{
acoral_print("Err Sem post\n");
acoral_Exit_critical();
return SEM_ERR_UNDEF;
}
timeout_queue_del(thread);
acoral_evt_queue_del(thread);
acoral_rdy_thread(thread);
acoral_exit_critical();
acoral_sched();
return SEM_SUCCED;
}
同步機制
信號量機制不僅可以實現(xiàn)臨界資源互斥訪問,控制系統(tǒng)中臨界資源多個實例的使用,還可以用于維護線程之間、線程和中斷之間的同步。
當信號量用來實現(xiàn)同步時,其初始值為0,如一個線程正等待某個I/O操作,當該I/O操作完成后,中斷服務程序發(fā)出信號量,該線程得到信號量后才能繼續(xù)往下執(zhí)行。
某個線程將一直處于等待狀態(tài),除非獲取了其它線程發(fā)給它的信號量。
用于互斥的信號量初始值在創(chuàng)建時設置為1,此時1-semNum=0,是小于等于0的,表明當前沒有線程獲取該信號量。
而用于同步的信號量初始值在信號量創(chuàng)建時設置為0,此時1-semNum=1,是大于1的,表明同步尚未發(fā)生。文章來源:http://www.zghlxwxcb.cn/news/detail-719887.html
同步信號量的實現(xiàn)和互斥信號量是一樣的,只是創(chuàng)建時傳入的參數(shù)決定了是用于同步還是用于互斥。文章來源地址http://www.zghlxwxcb.cn/news/detail-719887.html
到了這里,關于嵌入式實時操作系統(tǒng)的設計與開發(fā)(信號量學習)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!