Ayu*_*nha 7 c++ linux multithreading semaphore condition-variable
一些内核提供对信号量的“刷新”操作以解除对等待信号量的所有任务的阻塞。
例如,VxWorks 有一个semFlush() API,它可以原子地解除对指定信号量上挂起的所有任务的阻塞,即所有任务在允许运行之前都将被解除阻塞。
我正在 Linux 上实现一个 C++ 类,它的行为类似于二进制信号量,并且还具有这种“刷新”功能。不幸的是,Linux 上的semaphore.h不提供类似 API 的 flush() 或 broadcast() 。
我尝试过的:使用条件变量来实现二进制信号量。这是我的伪代码:
class BinarySem
{
BinarySem();
bool given;
mutex m;
condition_var cv;
give();
take();
take( Timeout T );
tryTake();
flush();
}
BinarySem::BinarySem()
: given(false)
{}
// take(Timeout T), tryTake() not shown
// to make question concise on StackOverflow
BinarySem::give()
{
{
lock_guard lk(m);
given = true;
}
cv.notify_one();
}
BinarySem::flush()
{
{
lock_guard lk(m);
given = true;
}
cv.notify_all();
}
BinarySem::take()
{
unique_lock lk(m);
while(!given)
{
cv.wait(lk);
}
given = false;
lk.unlock();
}
Run Code Online (Sandbox Code Playgroud)
但是,这flush()不会以正确的方式运行。比如说,我们有 2 个线程在等待 BinarySem(即它们都调用了take())。让这些线程成为hiPrioThread和loPrioThread。
当flush()在BinarySem对象上调用时,hiPrioThread将退出take()并运行。当它产生时(hiPrioThread只是产生,它还没有退出),loPrioThread仍然无法运行,因为given现在false又是布尔值。需要布尔值来防止虚假唤醒。
相反,信号量的flush()函数应该只是解除所有线程的阻塞,只要有机会它们就可以运行。
如果我不在given = false末尾设置怎么办take()?这将使我的代码容易受到虚假唤醒的影响,然后多个线程在give()使用时可能会被解除阻塞。
有没有人有什么建议?
借用一些“CyclicBarrier”实现的概念,并有一个生成或循环计数器。
然后“刷新”信号量就推进了一代。每个接受者在等待之前都会记下其生成,并且接受者等待信号量given 或等待生成更改:
BinarySem::flush() {
{
lock_guard lk(m);
current_gen++; // "flush" all waiters from the previous gen
//given = true; // No need to give; the 'current' taker will do this when done
}
cv.notify_all();
}
BinarySem::take() {
lock_guard lk(m);
uint64_t my_generation = current_gen;
while (!given && my_generation == current_gen) {
cv.wait(lk);
}
if (my_generation == current_gen) {
given = false;
}
}
Run Code Online (Sandbox Code Playgroud)
(警告:未经测试)
| 归档时间: |
|
| 查看次数: |
198 次 |
| 最近记录: |