目錄
一 ucos-iii 信號量相關函數
創建信號量 | OSSemCreate() | OS_CFG_SEM_EN |
OS_SEM SwSem; OS_ERR err; OSSemCreate(&SwSem, “Switch Semaphore”, |
刪除信號量 | OSSemDel() |
OS_CFG_SEM_EN OS_CFG_SEM_DEL_EN |
OS_SEM SwSem; OS_ERR err; qty = OSSemDel(&SwSem,OS_OPT_DEL_ALWAYS, |
等待信號量 | OSSemPend() | OS_CFG_SEM_EN |
OS_SEM SwSem; OS_ERR err; ctr = OSSemPend(&SwSem,0, |
取消等待 | OSSemPendAbort() |
OS_CFG_SEM_EN OS_CFG_SEM_PEND_ABORT_EN |
OS_SEM SwSem; OS_ERR err; nbr_tasks = OSSemPendAbort(&SwSem, |
釋放信號量 | OSSemPost() | OS_CFG_SEM_EN |
OS_SEM SwSem; OS_ERR err; ctr = OSSemPost(&SwSem, |
強制設置信號量的值 | OSSemSet() |
OS_CFG_SEM_EN OS_CFG_SEM_SET_EN |
OS_SEM SwSem; OS_ERR err; OSSemSet(&SwSem,0,&err); |
二 使用信號量
使用信號量訪問共享資源:
如果一個資源被多個任務訪問,則在訪問前調用OSSemPend()請求資源,在訪問結束後調用OSSemPost ()函數釋放資源
OS_SEM MY_SEM; //定義一個信號量,用於訪問共享資源
uint8_t share_res[30]; //共享資源區
//創建一個信號量
OSSemCreate ((OS_SEM* )&MY_SEM, //指向信號量
(CPU_CHAR* )"MY_SEM", //信號量名字
(OS_SEM_CTR )1, //信號量值爲 1
(OS_ERR* )&err);
void sem0_task(void *p_arg)
{
OS_ERR err;
uint8_t task0_str[]="sem0 Running!";
p_arg = p_arg;
while(1)
{
printf("sem0_task:\r\n");
OSSemPend(&MY_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); // 請求信號量
memcpy(share_res,task0_str,sizeof(task0_str)); // 向共享資源區拷貝數據
OSTimeDly (100, OS_OPT_TIME_DLY, &err ); //相對性延時1000個時鐘節拍(1s)
OSSemPost (&MY_SEM,OS_OPT_POST_1,&err); // 釋放信號量
OSTimeDly (100, OS_OPT_TIME_DLY, &err ); //相對性延時1000個時鐘節拍(1s)
}
}
void sem1_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
uint8_t task1_str[]="sem1 Running!";
while(1)
{
printf("sem1_task:\r\n");
OSSemPend(&MY_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); // 請求信號量
memcpy(share_res,task1_str,sizeof(task1_str)); // 向共享資源區拷貝數據
OSTimeDly (100, OS_OPT_TIME_DLY, &err ); //相對性延時1000個時鐘節拍(1s)
OSSemPost (&MY_SEM,OS_OPT_POST_1,&err); // 釋放信號量
OSTimeDly (100, OS_OPT_TIME_DLY, &err ); //相對性延時1000個時鐘節拍(1s)
}
}
使用信號量訪問共享資源會導致優先級翻轉,所以一般不推薦使用,下面舉例說明:
1. 假設有ABC三個任務,優先級A>B>C,任務AC訪問共享資源“res”,任務B不訪問共享資源。
2. 現在C正在使用共享資源res,在使用過程中進行了任務調度,由於A的優先級最高,所以接下來執行任務A
3. 由於A需要訪問共享資源res,而res正在被C訪問,所以任務A進入掛起狀態,任務C繼續執行。
4. 此時任務C仍在訪問共享資源,任務A爲掛起態,任務B爲就緒態,所以當任務C進行了任務調度後,接下來執行任務B
在這種情況下,任務 A 的優先級實際上降到了任務 C 的優先級水平,任務 B 的優先級高於任務A。因爲任務 A 要一直等待直到任務C釋放其佔用的那個共享資源。這就是優先級反轉。
使用信號量實現任務同步:
任務一通過OSSemPost()發送信號量。
任務二通過OSSemPend()不斷請求信號量,如果沒有請求到信號量,則進行任務調度,執行下一個任務;如果請求到信號量,則繼續運行該任務。
OS_SEM SYNC_SEM; //定義一個信號量,用於訪問共享資源
//創建一個信號量
OSSemCreate ((OS_SEM* )&MY_SEM, //指向信號量
(CPU_CHAR* )"MY_SEM", //信號量名字
(OS_SEM_CTR )1, //信號量值爲 1
(OS_ERR* )&err);
void sem0_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(1)
{
OSSemPost(&SYNC_SEM,OS_OPT_POST_1,&err);//發送信號量
OSTimeDly (100, OS_OPT_TIME_DLY, &err );//延時
}
}
void sem1_task(void *p_arg)
{
OS_ERR err;
uint16_t num = 0;
p_arg = p_arg;
while(1)
{
OSSemPend(&SYNC_SEM,0,OS_OPT_PEND_BLOCKING,0,&err);// 請求信號量
num++;
printf("請求信號量次數: %d\r\n",num);
OSTimeDly (1000, OS_OPT_TIME_DLY, &err ); //延時
}
}
三 互斥量(互斥信號量)常用函數
創建互斥信號量 | OSMutexCreate() | OS_CFG_MUTEX_EN |
OS_MUTEX DispMutex; OS_ERR err; OSMutexCreate(&DispMutex, “Display Mutex”,&err); |
刪除互斥型信號量 | OSMutexDel() |
OS_CFG_MUTEX_EN OS_CFG_MUTEX_DEL_EN |
OS_MUTEX DispMutex; OS_ERR err; qty = OSMutexDel(&DispMutex, |
等待互斥型信號量 | OSMutexPend() | OS_CFG_MUTEX_EN |
OS_MUTEX DispMutex; OS_ERR err; CPU_TS ts; OSMutexPend(&DispMutex,0, |
取消等待 | OSMutexPendAbort() |
OS_CFG_MUTEX_EN OS_CFG_MUTEX_PEND_ABORT_EN |
OS_MUTEX DispMutex; OS_ERR err; qty = OSMutexPendAbort(&DispMutex, |
釋放互斥型信號量 | OSMutexPost() | OS_CFG_MUTEX_EN |
OS_MUTEX DispMutex; OS_ERR err; OSMutexPost(&DispMutex, |
四 使用互斥信號量訪問共享資源
OS_MUTEX TEST_MUTEX; //定義一個互斥信號量
uint8_t share_res[30]; //共享資源區
//創建一個互斥信號量
OSMutexCreate((OS_MUTEX* )&TEST_MUTEX,
(CPU_CHAR* )"TEST_MUTEX",
(OS_ERR* )&err);
void sem0_task(void *p_arg)
{
OS_ERR err;
uint8_t task0_str[]="sem0 Running!";
p_arg = p_arg;
while(1)
{
OSMutexPend (&TEST_MUTEX,0,OS_OPT_PEND_BLOCKING,0,&err);// 請求互斥信號量
memcpy(share_res,task0_str,sizeof(task0_str));
OSMutexPost(&TEST_MUTEX,OS_OPT_POST_NONE,&err);// 釋放互斥信號量
OSTimeDly (100, OS_OPT_TIME_DLY, &err );//延時
}
}
void sem1_task(void *p_arg)
{
OS_ERR err;
uint16_t num = 0;
uint8_t task1_str[]="sem1 Running!";
p_arg = p_arg;
while(1)
{
OSMutexPend (&TEST_MUTEX,0,OS_OPT_PEND_BLOCKING,0,&err);// 請求互斥信號量
memcpy(share_res,task1_str,sizeof(task1_str));
OSMutexPost(&TEST_MUTEX,OS_OPT_POST_NONE,&err);// 釋放互斥信號量
OSTimeDly (100, OS_OPT_TIME_DLY, &err );//延時
}
}
五 任務內置信號量相關函數
等待任務信號量 | OSTaskSemPend() |
OS_ERR err; ctr = OSTaskSemPend(100, |
|
取消等待任務信號量 | OSTaskSemPendAbort() | OS_CFG_TASK_SEM_PEND_ABORT_EN |
OS_TCB CommRxTaskTCB; OS_ERR err; aborted = OSTaskSemPendAbort(&CommRxTaskTCB, |
發送任務信號量 | OSTaskSemPost() |
OS_TCB CommRxTaskTCB; OS_ERR err; OS_SEM_CTR ctr; ctr = OSTaskSemPost(&CommRxTaskTCB, |
|
強行設置任務信號量計數 | OSTaskSemSet() |
OS_TCB TaskY; OS_ERR err; ctr = OSTaskSemSet(&TaskY,0,&err); |
六 使用任務內置信號量
使用任務信號量不需要再定義與創建信號量,一般用作同步功能,如下列所示:
extern OS_TCB SEM1TaskTCB;
void sem0_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(1)
{
OSTaskSemPost(&SEM1TaskTCB, OS_OPT_POST_NONE,&err); // 使用系統內建信號量向任務發送信號量
OSTimeDly (1000, OS_OPT_TIME_DLY, &err );//延時
}
}
void sem1_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(1)
{
OSTaskSemPend(0,OS_OPT_PEND_BLOCKING,0,&err); // 請求任務內建的信號量
printf("成功請求到內置信號量\r\n");
OSSched();
}
}