Liteos信号量的使用

26 篇文章 3 订阅
8 篇文章 2 订阅

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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值