【发布时间】:2021-12-28 07:14:29
【问题描述】:
实际上,我并不是要求线程必须“排队”才能工作,而是我只想通知多个线程。所以我不是在寻找障碍。
有点像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 中做到这一点?
对不起,我没有把这个问题说得足够清楚,我会补充一些解释。
我说的不是雷声问题,是的,困扰我的是re-acquire-lock,我试过shared_mutex,还是有问题。
让我将线程分成 2 个部分,1 个作为领导线程,负责写入工作,其他作为工作线程,负责读取工作。
但实际上它们在程序中都是平等的,领导线程是第一个访问作业的线程(您可以将其视为该线程的共享缓冲区下溢)。工作完成后,只需要通知其他工作人员他们可以访问。
如果在这里使用mutex,任何线程都会阻塞其他线程。
举个例子:主线程的jobdo_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();
}
});
}
}
在这段代码中,如果领导者的工作已经完成,并且在 unlock 和下一个 lock 之间没有太多可做的事情(记住它们处于循环中),它可能会再次获得锁,离开工作人员的工作不工作,这就是为什么我之前称之为starve。
为了解释do_something()中的阻塞,我不希望这部分工作占用我所有的CPU时间,即使领导者的工作还没有准备好(read没有数据到达)
和std::call_once 可能仍然不是这个问题的答案。因为如你所见,工人必须等到领导的工作完成。
总而言之,这实际上是一个生产者多消费者的问题。 但我希望消费者能够在产品准备就绪时完成这项工作。 any 可以是生产者或消费者。如果除了第一个发现产品已经用完,线程应该是生产者,因此其他人自动成为消费者。
但不幸的是,我不确定这个想法是否可行
【问题讨论】:
-
也许我只是对实现细节不够了解,但是但我不希望线程一个接一个地唤醒,这可能会导致饥饿听起来像假设。或者你没有充分解释你的意思。
-
只是不要假设操作系统可以变魔术。最后的操作系统是一个由凡人编写的程序,因此它无法完成您的要求。
-
我编辑了问题来解释自己
-
您是否在寻找
std::call_once? -
“唤醒一一”而不是?
标签: c++ multithreading