Liteos信号量的使用
Liteos的信号量和其他的OS一样,分为二值信号量和计数信号量。
创建信号量
创建二值信号量和计数信号量时提供了两个函数:
//创建二值信号量
LITE_OS_SEC_TEXT_INIT UINT32 LOS_BinarySemCreate (UINT16 usCount, UINT32 *puwSemHandle)
//创建计数信号量
LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemCreate (UINT16 usCount, UINT32 *puwSemHandle)
//实际创建信号量
LITE_OS_SEC_TEXT_INIT UINT32 osSemCreate (UINT16 usCount, UINT16 usMaxCount, UINT32 *puwSemHandle)
这两个函数都是通过调用osSemCreate()函数来实现创建信号量,唯一的区别就是传入的usMaxCount值不同。二值信号量传入的宏定义是OS_SEM_BINARY_MAX_COUNT,也就是说最大可用信号量是1,而计数信号量传入的是OS_SEM_COUNTING_MAX_COUNT,这个值为0xFFFF。
二值信号量的使用方式很简单,通过创建时传入的usCount来指定信号量创建后的初始可用信号量值,如果设置为1,那么任务就可以直接获取到信号量。计数信号量的用法也是一样,但是可以一直Post,直到最大值OS_SEM_COUNTING_MAX_COUNT。
计数信号量测试
在创建信号量之前需要先仿照消息队列的LOS_QueueInfoGet()函数来写一个用来获取信号量控制块的具体内容函数,主要看一下可用信号量个数和最大可用信号量个数:
LITE_OS_SEC_TEXT UINT32 LOS_SemInfoGet(UINT32 uwSemHandle,SEM_CB_S *pstSemInfo)
{
UINT32 uvIntSave;
UINT32 uwRet = LOS_OK;
SEM_CB_S *pstSem;
LOS_TASK_CB *pstTskCB;
if (uwSemHandle >= (UINT32)LOSCFG_BASE_IPC_SEM_LIMIT)
{
OS_RETURN_ERROR(LOS_ERRNO_SEM_INVALID);
}
pstSem = GET_SEM(uwSemHandle);
uvIntSave = LOS_IntLock();
if (OS_SEM_UNUSED == pstSem->usSemStat)
{
LOS_IntRestore(uvIntSave);
OS_RETURN_ERROR(LOS_ERRNO_SEM_INVALID);
}
(VOID)memset((VOID *)pstSemInfo, 0, sizeof(SEM_CB_S));
pstSemInfo->usSemID = pstSem->usSemID;
pstSemInfo->usSemStat = pstSem->usSemStat;
pstSemInfo->usSemCount = pstSem->usSemCount;
pstSemInfo->usMaxSemCount = pstSem->usMaxSemCount;
(VOID)LOS_IntRestore(uvIntSave);
return LOS_OK;
}
直接用LOS_SemCreate()函数创建一个计数信号量,初始可用信号量个数为5,创建后立刻Post5次,并在Post前后将可用信号量个数和最大可用信号量个数打印出来:
UINT32 test_countsem_handle;
SEM_CB_S pstSemInfo;
uwRet = LOS_SemCreate(5,&test_countsem_handle);
if(uwRet != LOS_OK)
{
PRINT_ERR("Sem Error Code:0x%X\n",uwRet);
return uwRet;
}
uwRet = LOS_SemInfoGet(test_countsem_handle,&pstSemInfo);
if(uwRet == LOS_OK)
{
PRINT_INFO("Sem Count:%d\r\n",pstSemInfo.usSemCount);
PRINT_INFO("Sem CountMax:%d\r\n",pstSemInfo.usMaxSemCount);
}
uwRet = LOS_SemPost(test_countsem_handle);
if(uwRet != LOS_OK)
{
PRINT_ERR("Post Sem Error:0x%X\n",uwRet);
}
uwRet = LOS_SemPost(test_countsem_handle);
if(uwRet != LOS_OK)
{
PRINT_ERR("Post Sem Error:0x%X\n",uwRet);
}
uwRet = LOS_SemPost(test_countsem_handle);
if(uwRet != LOS_OK)
{
PRINT_ERR("Post Sem Error:0x%X\n",uwRet);
}
uwRet = LOS_SemPost(test_countsem_handle);
if(uwRet != LOS_OK)
{
PRINT_ERR("Post Sem Error:0x%X\n",uwRet);
}
uwRet = LOS_SemPost(test_countsem_handle);
if(uwRet != LOS_OK)
{
PRINT_ERR("Post Sem Error:0x%X\n",uwRet);
}
uwRet = LOS_SemInfoGet(test_countsem_handle,&pstSemInfo);
if(uwRet == LOS_OK)
{
PRINT_INFO("Sem Count:%d\r\n",pstSemInfo.usSemCount);
PRINT_INFO("Sem CountMax:%d\r\n",pstSemInfo.usMaxSemCount);
}
创建一个任务,这个任务只获取信号量,最大只能获取5次,任务主要内容:
UINT32 uwRet = LOS_OK;
UINT32 count = 0;
LOS_TaskDelay(400);//2s
uwRet = LOS_SemPend(test_countsem_handle,LOS_NO_WAIT);
if(uwRet != LOS_OK)
{
PRINT_ERR("Pend Sem Error:0x%X\n",uwRet);
}
else
{
PRINT_INFO("Pend Sem Ok = %d\r\n",(++count));
}
按照期望来说,Pend信号量只能成功5次,但是实际运行结果却是10次,通过日志也可以看出来Post5次之后,可用信号量个数增加了5;Pend10次之后,下一次就不能成功了,因为没有可用信号量,错误码0x2000704,7表示是信号量产生的错误,4表示没有可用信号量,宏定义为LOS_ERRNO_SEM_UNAVAILABLE。
原因就是LOS_SemPost()函数中会有pstSemPosted->usMaxSemCount == pstSemPosted->usSemCount这个判断,就是比较可用信号量个数和最大可用信号量个数是否相等,如果相等的话就直接返回,无需Post,但是OS_SEM_COUNTING_MAX_COUNT这个值为0xFFFF,因此可以一直Post直到最大值。使用LOS_BinarySemCreate()函数创建二值信号量时就没有这个问题。
创建计数信号量时直接调用osSemCreate()函数或者更改OS_SEM_COUNTING_MAX_COUNT的值为5时,运行结果就和期望结果一致:
uwRet = osSemCreate(5,5,&test_countsem_handle);
由于可用信号量个数和最大可用信号量个数相等,在创建信号量之后Post时返回了错误码0x2000708,8表示溢出,宏定义为LOS_ERRNO_SEM_OVERFLOW;在Pend5次之后由于没有可用信号量,返回错误LOS_ERRNO_SEM_UNAVAILABLE。