前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Task之计数信号量

Task之计数信号量

作者头像
Taishan3721
发布2019-07-10 15:31:26
8730
发布2019-07-10 15:31:26
举报
文章被收录于专栏:这里只有VxWorks这里只有VxWorks

在<Task之二进制信号量>里提到过二进制信号量用来解决同步问题。下面看一个同步的例子

这段代码很简单,大致的意思就是每成功申请一次信号量,就打印一句话

启动一个任务(t1)来调用这个函数:

可以看到t1阻塞到信号量semId上了。直接给它释放一次信号量

任务(t1)打印了一句话,说明收到了一次信号量

接下来试试释放两次信号量,可以用Shell的命令repeat()

任务(t1)也打印了两句话,说明收到了两次信号量

接下来试试多次的

可以看到, repeat的次数大于2之后,任务(t1)都是只能收到两次信号量

我们看看semGive()的操作流程

从上图可以看到,repeat()第一次释放信号量时,它会将阻塞状态的t1置为就绪状态。第二次释放时,没有任务阻塞了,于是将信号量置为有效(0->1),之后再释放时,都是将信号量置有效(1->1)。直到repeat()执行完毕,就绪状态的t1开始执行后续操作,出现第一次打印。然后又可以成功申请一次信号量(1->0),就有了第二次打印。这之后,信号量就又是无效的了,t1再次进入了阻塞状态

这就是二进制信号量的特点,它是用来表示事件是否发生了,而不能表示事件发生的次数

如果需要记录事件发生的次数呢?可以试试提高t1的优先级

不过VxWorks专门提供了用于计数的信号量: 计数信号量

semCCreate()用来动态创建计数信号量,semCInit()用来初始化静态分配的信号量

initCount表示计数信号量的初值,因为是有符号整型值,其取值范围是0-2147483647(0x0-0x7fffffff)

而具体的使用,与二进制信号量非常像

semTake()用来申请信号量,信号量无效时,引起阻塞,因此不能在ISR中使用

semGive()用来释放信号量,在任务或ISR中都可以调用

与二进制信号量不同的是,计数信号量的值不是在0和1之间变化,而是用一个count来记录具体数值。而且目前count的值可以超过2147483647(0x7fffffff)

超过之后,semGive()和semTake()还可以正常操作。只是show()操作时,只能看到低31位的值

从源码里可以看到,只有count超过4294967295(0xffffffff)时,才会溢出。看来这应该是VxWorks的一个小bug了

Anyway,实际应用中,count的值不太可能那么大的。还是回到开始位置,把testSemB那个例子改了看看吧

这时候再多次释放信号量,任务(t1)就可以收到多次了

同时,计数信号量也支持semFlush()操作,即它也是可以用于多任务同步的。

最后跑一个静态初始化的例子吧

mySem是在编译时就分配空间了,semCInit()里就不用在动态申请内存了

这正是:

两种信号量,不分弱与强。

同步或计数,用时细端详。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 这里只有VxWorks 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档