一个 cpp 协程库的前世今生(十四)信号量与条件变量
为了防止大家找不到代码,还是先贴一下项目链接:
GitHub - skyfireitdiy/cocpp at cocpp-0.1.0
上一篇文章介绍了互斥量的实现,本篇文章继续介绍信号量和条件变量。
信号量分为计数信号量和二值信号量,二值信号量是计数信号量的一个特化。
条件变量
条件变量的定义非常简单,在 include/cocpp/sync/co_condition_variable.h 中:
可以看到,co_condition_variable 其实就是 std::condition_variable_any 的别名,std::condition_variable_any 可以等待任何带有 lock 和 unlock 接口的对象,因此我们就可以将实现的协程锁作为他的入参对象,它本身并不区分是哪一种类型的锁。
计数信号量
计数信号量的典型应用场景是生产者消费者,信号量的计数代表着资源的个数。
接口
信号量的接口位于 include/cocpp/sync/co_counting_semaphore.h
信号量的接口比互斥量要复杂的多,接下来我们看一下这些接口的用途。
acquire:获取一个资源,计数减 1,在获取不到时会阻塞,直到获取成功为止
release:释放一个或多个资源,参数的默认为 1,意味着释放一个资源,如果资源数量已经到达 LeastMaxValue,则会阻塞,直到资源被消费。
try_acquire:尝试获取一个资源,如果获取不到,返回 false。
try_acquire_for 与 try_acquire_until:在指定时间段内或者是指定时间点前尝试获取资源,如果一直获取不到,返回 false
max:返回最大可容纳的资源数量,这是一个 constexpr 函数
构造函数:构造函数带有一个值,表示默认的资源数量
接下来我们再看那几个私有成员变量
mu__:用来保护资源计数的互斥量
empty_cond__:资源为空时,等待的条件变量
full_cond__:资源为满时,等待的条件变量
desired__:当前的资源计数
release_one__:释放一个资源
实现
信号量的实现比较复杂,接下来我们一一来看。
acquire
acquire 的实现如下(include/cocpp/sync/co_counting_semaphore.h):
此处先获取到操作计数的互斥量。
然后判断当前是否有可用的资源,如果没有,就使用条件变量等待,直到有可用资源为止。
然后将可用资源数量减 1。
然后通知 full_cond__对应的等待者可以放资源了。
接下来看一下 release 的做法。
release
实现如下(include/cocpp/sync/co_counting_semaphore.h):
其中 release_one__与 acquire 是类似的,这里不做赘述。
可以看到,因为 release 支持同时释放多个资源,因此它是多次调用 release_one__。
其余的几个接口都很简单,这里就不一一介绍了。
二值信号量
顾名思义,二值信号量就是只有一个空间的信号量,定义如下(include/cocpp/sync/co_binary_semaphore.h):
总结
本文介绍的条件变量与信号量的实现。其中条件变量其实就是 std::condition_variable_any,并不关心底层的操作对象。而计数信号量是典型的生产者消费者写法,二值信号量是计数信号量的一个特例。
版权声明: 本文为 InfoQ 作者【SkyFire】的原创文章。
原文链接:【http://xie.infoq.cn/article/b1859904d4004c75b55b35a33】。文章转载请联系作者。
评论