当前位置: 首页 > news >正文

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。

相关文章:

  • 基于Verilog搭建一个卷积运算单元的简单实现
  • pytorch-实现mnist手写数字识别(彩色)
  • C/C++语言100题练习计划 99——找第一个只出现一次的字符
  • Go使用Gin+mysql实现增删改查
  • PIE-Engine:房山区洪涝灾害风险评价
  • 【我的渲染技术进阶之旅】如何编译Filament的windows版本程序?
  • 03 C++ 字符串、向量和数组
  • python 代码 C 执行
  • 字节外包凭借【ui自动化测试框架】成功进入内部编制
  • 用 Plop 加快项目相似代码生成
  • Codeforces Round #822 (Div. 2) 补题 (A、B、C)
  • 【初阶与进阶C++详解】第十六篇:AVL树-平衡搜索二叉树(定义+插入+旋转+验证)
  • 去除多重共线性的5种方法,你学废了嘛?
  • Verilog的奇技淫巧[更新中]
  • 被CTO推荐的SQL总结
  • Angular6错误 Service: No provider for Renderer2
  • bearychat的java client
  • es6要点
  • JavaScript 奇技淫巧
  • SpriteKit 技巧之添加背景图片
  • vagrant 添加本地 box 安装 laravel homestead
  • v-if和v-for连用出现的问题
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 开源SQL-on-Hadoop系统一览
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 设计模式 开闭原则
  • ​Java并发新构件之Exchanger
  • ​马来语翻译中文去哪比较好?
  • ![CDATA[ ]] 是什么东东
  • #define用法
  • #Ubuntu(修改root信息)
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (C)一些题4
  • (四)鸿鹄云架构一服务注册中心
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • (转)编辑寄语:因为爱心,所以美丽
  • (转)创业的注意事项
  • **CI中自动类加载的用法总结
  • 、写入Shellcode到注册表上线
  • .bat文件调用java类的main方法
  • .Net 6.0 处理跨域的方式
  • .net 怎么循环得到数组里的值_关于js数组
  • .NET单元测试
  • .project文件
  • .vue文件怎么使用_vue调试工具vue-devtools的安装
  • /usr/bin/env: node: No such file or directory
  • @Pointcut 使用
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042
  • []指针
  • [2669]2-2 Time类的定义
  • [BZOJ 4129]Haruna’s Breakfast(树上带修改莫队)
  • [C++] Windows中字符串函数的种类
  • [Django 0-1] Core.Handlers 模块