是否有任何方法可以在c/c++中同时唤醒多个线程



实际上,我并不是要求线程必须"排队";工作,但我只想通知多个线程。所以我不是在找障碍。

它有点像condition_variable::notify_all(),但我不希望线程一个接一个地唤醒,这可能会导致饥饿(也是多信号量后操作中的潜在问题(。有点像:

std::atomic_flag flag{ATOMIC_FLAG_INIT};
void example() {
if (!flag.test_and_set()) {
//  this is the thread to do the job, and notify others
do_something();
notify_others(); // this is what I'm looking for
flag.clear();
} else {
//  this is the waiting thread
wait_till_notification();
do_some_other_thing();
}
}
void runner() {
std::vector<std::threads>;
for (int i=0; i<10; ++i) {
threads.emplace_back([]() {
while(1) {
example();
}
});
}
// ...
}

那么我如何在c/c++或posix API中实现这一点呢?


对不起,我没有把这个问题说清楚,我想补充一些解释。

我说的不是雷声大的问题,是的,困扰我的是重新获取锁,我尝试了shared_mutex,仍然有一些问题。

让我把线程分为两部分,一部分作为引导线程,负责编写工作,另一部分作为辅助线程,负责读取工作。

但实际上它们在程序中都是相等的,引导线程是第一个访问作业的线程(您可以将其视为该线程的共享缓冲区下溢(。一旦工作完成,只需要通知其他工作人员他们有访问权限。如果这里使用mutex,任何线程都会阻塞其他线程。举个例子:这里主线程的作业do_something()是一个read,它阻塞了主线程,从而阻塞了整个系统。

不幸的是,shared_mutex无法解决这个问题:

void example() {
if (!flag.test_and_set()) {
// leader thread:
lk.lock();
do_something();
lk.unlock();
flag.clear();
} else {
// worker thread
lk.shared_lock();
do_some_other_thing();
lk.shared_unlock();
}
}
// outer loop
void looper() {
std::vector<std::threads>;
for (int i=0; i<10; ++i) {
threads.emplace_back([]() {
while(1) {
example();
}
});
}
}

在这段代码中,如果leader作业已经完成,并且在这个unlock和下一个lock之间没有太多事情要做(记住它们在循环中(,它可能会再次获得锁,使worker作业不起作用,这就是为什么我以前称它为starve

为了解释do_something()中的阻塞,我不希望这部分工作占用我所有的CPU时间,即使领导的工作还没有准备好(read没有数据到达(

并且CCD_ 12可能仍然不是对此的答案。因为,正如你所看到的,工人们必须等到领导的工作完成。

总之,这实际上是一个一生产者多消费者的问题。但我希望消费者能够在产品为他们准备好时完成这项工作。任何人都可以是生产者或消费者。如果除了第一个发现产品已经用完之外,其他线程应该是生产者,因此其他线程自动成为消费者。

但不幸的是,我不确定这个想法是否可行

它有点像condition_variable::notify_all(),但我不希望线程一个接一个地唤醒,这可能会导致饥饿

原则上,序列化的不是唤醒,而是重新获取锁。

您可以通过将std::condition_variable_anystd::shared_lock一起使用来避免这种情况——只要没有人在std::shared_mutex上获得独占锁。或者,您可以提供自己的可锁定类型。

然而,请注意,这不会神奇地允许您并发运行比核心更多的线程,也不会强制调度程序启动所有并行运行的线程。它们将被标记为可运行,并按正常方式进行调度——这只会修复您自己代码中可避免的序列化。

听起来你在寻找call_once

#include <mutex>
void example()
{
static std::once_flag flag;
bool i_did_once = false;
std::call_once(flag, [&i_did_once]() mutable {
i_did_once = true;
do_something();
});
if(! i_did_once)
do_some_other_thing();
}

我不明白你的问题与饥饿有什么关系。你可能在考虑雷电群的问题吗?如果do_some_other_thing有一个互斥,可能会出现这种情况,但在这种情况下,您必须更详细地描述您的问题。

最新更新