版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tiantao2012/article/details/86651426
sem就是信号量,其使用如下所示:
在使用sem之前先要创建sem
LOS_SemCreate(0, &g_usSemID);
创建后,就可以调用LOS_SemPend 来得到一个信号量,调用LOS_SemPost 释放一个信号量
static VOID Example_SemTask1(VOID)
{
UINT32 uwRet;
dprintf("Example_SemTask1 try get sem g_usSemID ,timeout 10 ticks.\n");
/* get sem, timeout is 10 ticks */
#获取信号量
uwRet = LOS_SemPend(g_usSemID, 10);
/* get sem ok */
if (LOS_OK == uwRet)
{
#成功获取后释放信号量
LOS_SemPost(g_usSemID);
return;
}
}
下来我们具体看看如何获取信号量
LITE_OS_SEC_TEXT UINT32 LOS_SemPend(UINT32 uwSemHandle, UINT32 uwTimeout)
{
UINT32 uwIntSave;
SEM_CB_S *pstSemPended;
UINT32 uwRetErr;
LOS_TASK_CB *pstRunTsk;
pstSemPended = GET_SEM(uwSemHandle);
#得到正在运行的task
pstRunTsk = (LOS_TASK_CB *)g_stLosTask.pstRunTask;
#将要得到的信号量赋值给当前进程
pstRunTsk->pTaskSem = (VOID *)pstSemPended;
#将这个进程插入到pendlist中,并建立一个timer来唤醒这个进程得到信号量
osTaskWait(&pstSemPended->stSemList, OS_TASK_STATUS_PEND, uwTimeout);
(VOID)LOS_IntRestore(uwIntSave);
#释放cpu
LOS_Schedule();
if (pstRunTsk->usTaskStatus & OS_TASK_STATUS_TIMEOUT)
{
uwIntSave = LOS_IntLock();
pstRunTsk->usTaskStatus &= (~OS_TASK_STATUS_TIMEOUT);
uwRetErr = LOS_ERRNO_SEM_TIMEOUT;
goto errre_uniSemPend;
}
#规定的时间内信号量被唤醒,没有timeout则返回成功
return LOS_OK;
#否则返回失败,获取信号量失败
errre_uniSemPend:
(VOID)LOS_IntRestore(uwIntSave);
OS_RETURN_ERROR(uwRetErr);
}
LITE_OS_SEC_TEXT VOID osTaskWait(LOS_DL_LIST *pstList, UINT32 uwTaskStatus, UINT32 uwTimeOut)
{
LOS_TASK_CB *pstRunTsk;
LOS_DL_LIST *pstPendObj;
pstRunTsk = g_stLosTask.pstRunTask;
osPriqueueDequeue(&pstRunTsk->stPendList);
pstRunTsk->usTaskStatus &= (~OS_TASK_STATUS_READY);
pstPendObj = &pstRunTsk->stPendList;
pstRunTsk->usTaskStatus |= uwTaskStatus;
#将这个进程插入到pendlist中
LOS_ListTailInsert(pstList,pstPendObj);
if (uwTimeOut != LOS_WAIT_FOREVER)
{
pstRunTsk->usTaskStatus |= OS_TASK_STATUS_TIMEOUT;
#建立一个timer在规定时间内唤醒这个进程
osTaskAdd2TimerList((LOS_TASK_CB *)pstRunTsk, uwTimeOut);
}
}
释放信号量的函数分析如下:
LITE_OS_SEC_TEXT UINT32 LOS_SemPost(UINT32 uwSemHandle)
{
UINT32 uwIntSave;
SEM_CB_S *pstSemPosted = GET_SEM(uwSemHandle);
LOS_TASK_CB *pstResumedTask;
#需要释放的信号量不为null的话
if (!LOS_ListEmpty(&pstSemPosted->stSemList))
{
#从需要释放信号量的list中找到第一个task
pstResumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(pstSemPosted->stSemList))); /*lint !e413*/
#将要唤醒的task的sem置空
pstResumedTask->pTaskSem = NULL;
#开始唤醒task
osTaskWake(pstResumedTask, OS_TASK_STATUS_PEND);
#恢复中断
(VOID)LOS_IntRestore(uwIntSave);
#启动调度
LOS_Schedule();
}
else
{
#从这里可以知道信号量可以分别获取和释放多次
pstSemPosted->usSemCount++;
(VOID)LOS_IntRestore(uwIntSave);
}
return LOS_OK;
}