【发布时间】:2021-11-19 16:38:01
【问题描述】:
我正在编写一个使用条件变量的程序:
bool flag;
std::mutex mtx;
std::condition_variable cond;
{
std::unique_lock<std::mutex> lock(mtx);
cond.wait(lock, [&]{ return flag; });
// ... do some stuff
// ... do some more stuff
flag = false;
} // lock unlocked here
现在我面临的问题是“做一些事情”和“做更多事情”实际上是在两个单独的回调函数中实现的,这些函数从其他地方一个接一个地调用,即:
void callback1() {
std::unique_lock<std::mutex> lock(mtx);
cond.wait(lock, [&]{ return flag; });
// ... do some stuff
} // ERROR! lock unlocked too early
void callback2() {
// ... do some more stuff
flag = false;
} // lock should be unlocked here
我该如何解决这个问题?我可以将这两个回调封装在某个将锁作为成员变量保存的对象中,但在我看来,这违反了std::unique_lock 的预期语义。
编辑:更多上下文:
其他人编写了一个类Foo,如下所示:
class Foo
{
public:
void bar() {
before_bar_callback();
// ...
after_bar_callback();
}
private:
virtual void before_bar_callback() {}
virtual void after_bar_callback() {}
};
我无法修改Foo::bar,它在单独的线程中运行。我想等待before_bar_callback 中的条件变量,然后设置flag = false 并解锁after_bar_callback 中的关联锁。
【问题讨论】:
-
这些信息不足以得出一个平衡的答案。为什么是 2 个回调而不是 1 个。如果他们如此依赖,我认为他们应该合二为一。
-
@PKramer 我添加了更多上下文。
-
我想我知道你在做什么。如果我理解正确,您希望两个回调基本上都是原子的,因为您不想冒两者之间“无效”的风险。我参与了一个处理这个问题的项目,他们最终决定在回调之间解锁是可以的。否则你最终会陷入各种奇怪的死锁场景。现实情况是该程序的多线程并不足以导致错误(但它确实发生了)。在此之后,我认为唯一的解决方案是使用异步事件,这会带来其自身的挑战。
-
使用那个分割界面,你不能使用 RAII :/
-
您可以使用
std::condition_variable_any并将mtx直接传递给它的wait。这样callback1返回时不会自动解锁。
标签: c++ multithreading c++11 concurrency