【发布时间】:2022-01-25 03:39:46
【问题描述】:
在我的代码中,我想使用std::atomic_flag 来同步两个线程。具体来说,我想使用 C++20 中引入的新 wait 和 notify_all 功能。
简而言之:一个线程正在等待标志准备好,而另一个线程将设置标志并发出通知。然而,问题是atomic_flag 存在于堆栈中,将在通知后被销毁,而第一个线程可能仍在对wait 的调用中。
基本上,我有相当于以下sn-p的东西:
#include <atomic>
#include <thread>
int main(int, char**)
{
auto t = std::thread{};
{
auto f = std::atomic_flag{};
t = std::thread{[&f] { f.wait(false); }};
// Ensures that 't' is waiting on 'f' (not 100% guarantee, but you get the point)
std::this_thread::sleep_for(std::chrono::milliseconds{50});
f.test_and_set();
f.notify_all();
} // <--- 'f' is destroyed here but 't' may still be in the wait call
t.join();
return 0;
}
过去,我曾在此类情况下使用过boost::latch,我从经验中知道这种模式几乎总是会崩溃或断言。但是,将 boost::latch 替换为 std::atomic_flag 不会导致任何崩溃、断言或死锁。
我的问题:在调用notify_all 之后销毁std::atomic_flag 是否安全(即唤醒线程可能仍在wait 方法中)?
【问题讨论】:
-
我相信这是一场比赛。
wait被定义为在唤醒后检查标志的值,将其与其参数进行比较(并且可能重新进入睡眠状态)。这将与析构函数竞争。 -
@IgorTandetnik 是的,确实如此。我已经设法相当快地打破了工作代码 sn-p 使其陷入僵局。在读取原子标志值的唤醒线程和破坏原子标志的销毁线程之间确实存在竞争。在 C++ 标准中,wait 的效果也描述了在唤醒之后,线程会再次读取 flag 的值。
标签: c++ multithreading atomic c++20 lifetime