ucos-iii 信號量、互斥信號量

目錄

一  ucos-iii 信號量相關函數

二  使用信號量

三  互斥量(互斥信號量)常用函數

四  使用互斥信號量訪問共享資源

五  任務內置信號量相關函數

六   使用任務內置信號量


一  ucos-iii 信號量相關函數

創建信號量 OSSemCreate() OS_CFG_SEM_EN

OS_SEM SwSem;

OS_ERR err;

OSSemCreate(&SwSem, “Switch Semaphore”,
                         0,&err);

刪除信號量 OSSemDel()  

OS_CFG_SEM_EN

OS_CFG_SEM_DEL_EN

OS_SEM SwSem;

OS_ERR err;
OS_OBJ_QTY qty;

qty = OSSemDel(&SwSem,OS_OPT_DEL_ALWAYS,
           &err);

等待信號量 OSSemPend() OS_CFG_SEM_EN

OS_SEM SwSem;

OS_ERR err;
CPU_TS ts;
OS_SEM_CTR ctr;

ctr = OSSemPend(&SwSem,0,
               OS_OPT_PEND_BLOCKING,&ts,&err);

取消等待 OSSemPendAbort()

OS_CFG_SEM_EN

OS_CFG_SEM_PEND_ABORT_EN

OS_SEM SwSem;

OS_ERR err;
OS_OBJ_QTY nbr_tasks;

nbr_tasks = OSSemPendAbort(&SwSem,
                OS_OPT_PEND_ABORT_ALL,&err);

釋放信號量 OSSemPost()  OS_CFG_SEM_EN

OS_SEM SwSem;

OS_ERR err;
OS_SEM_CTR ctr;

ctr = OSSemPost(&SwSem,
OS_OPT_POST_1 +OS_OPT_POST_NO_SCHED,
&err);

強制設置信號量的值 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;
OS_OBJ_QTY qty;

qty = OSMutexDel(&DispMutex,
                    OS_OPT_DEL_ALWAYS,&err);

等待互斥型信號量 OSMutexPend() OS_CFG_MUTEX_EN

OS_MUTEX DispMutex;

OS_ERR err;

CPU_TS ts;

OSMutexPend(&DispMutex,0,
        OS_OPT_PEND_BLOCKING,&ts,&err);

取消等待 OSMutexPendAbort()

OS_CFG_MUTEX_EN

OS_CFG_MUTEX_PEND_ABORT_EN

OS_MUTEX DispMutex;

OS_ERR err;
OS_OBJ_QTY qty;

qty = OSMutexPendAbort(&DispMutex,
            OS_OPT_PEND_ABORT_ALL,&err);

釋放互斥型信號量 OSMutexPost() OS_CFG_MUTEX_EN

OS_MUTEX DispMutex;

OS_ERR err;

OSMutexPost(&DispMutex,
                    OS_OPT_POST_NONE,&err);

四  使用互斥信號量訪問共享資源

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;
OS_SEM_CTR ctr;
CPU_TS ts;

ctr = OSTaskSemPend(100,
         OS_OPT_PEND_BLOCKING,
         &ts,&err);

取消等待任務信號量 OSTaskSemPendAbort()  OS_CFG_TASK_SEM_PEND_ABORT_EN

OS_TCB CommRxTaskTCB;

OS_ERR err;
CPU_BOOLEAN aborted;

aborted = OSTaskSemPendAbort(&CommRxTaskTCB,
OS_OPT_POST_NONE,&err);

發送任務信號量 OSTaskSemPost()   

OS_TCB CommRxTaskTCB;

OS_ERR err;

OS_SEM_CTR ctr;

ctr = OSTaskSemPost(&CommRxTaskTCB,
                    OS_OPT_POST_NONE,&err);

強行設置任務信號量計數 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();  
    }
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章