std::atomic 和 std::condition_variable 等待、notify_* 方法的区别

PVR*_*VRT 12 c++ condition-variable stdatomic c++20

我正在浏览“原子操作库”,并遇到了原子“等待”和“notify_ ”方法的新 C++20 功能我很好奇 std::condition_variable 的 'wait' 和 'notify_ ' 方法有何不同

Ale*_*iev 7

整个使用模式有所不同。

condition_variable等待需要互斥锁。在通知之前应该使用相同的互斥锁:

std::mutex mtx;
std::condition_variable cv;

bool condition();
void change_condition();

...

std::unique_lock<std::mutex> lock(mtx);
while (!condition())
{
   cv.wait(lock);
}

...

std::unique_lock<std::mutex> lock(mtx);
change_condition();
lock.unlock();
cv.notify_one();
Run Code Online (Sandbox Code Playgroud)

现在,如果您有带有条件变量的原子,您仍然需要锁定:

std::mutex mtx;
std::condition_variable cv;

std::atomic<bool> condition;

...

std::unique_lock<std::mutex> lock(mtx);
while (!condition.load())
{
   cv.wait(lock);
}

...

std::unique_lock<std::mutex> lock(mtx);
condition.store(true);
lock.unlock();
cv.notify_one();
Run Code Online (Sandbox Code Playgroud)

Atomic 本身不需要加锁保护,因此可以在不加锁的情况下进行修改。但是,仍然需要互斥锁来与等待同步并避免丢失唤醒。唤醒线程的替代方法如下:

condition.store(true);
std::unique_lock<std::mutex> lock(mtx);
lock.unlock();
cv.notify_one();
Run Code Online (Sandbox Code Playgroud)

互斥锁不能省略,即使在通知端也是如此。

(并且您无法摆脱condiion_variable_any在其lock/中不执行任何操作的“空互斥锁” unlock)。


现在,原子等待。除了在另一个答案中提到的没有虚假唤醒之外,不需要互斥锁:


std::atomic<bool> condition;

...

condition.wait(false);

...

condition.store(true);
condition.notify_one();
Run Code Online (Sandbox Code Playgroud)


ale*_*ame 6

STD:原子waitnotify_all并且notify_one方法类似于条件变量的方法。它们允许通过使用更高效和轻量级的原子变量来实现以前需要条件变量的逻辑。

wait函数阻塞线程,直到原子对象的值被修改。它需要一个参数来与原子对象的值进行比较。它反复执行:

  • 如果值相等,它会阻塞线程直到被notify_one或通知notify_all,或者线程被虚假地解除阻塞。
  • 否则,返回。

注意:wait保证仅在值已更改时返回,即使底层实现虚假地解除阻塞。


您可以在此处找到实现:https : //github.com/ogiroux/atomic_wait/

策略是这样选择的,按平台:

  • Linux:默认为 futex(带表),回退到 futex(无表)-> CVs -> 定时退避 -> 自旋。
  • Mac:默认为 CV(表格),回退到定时退避 -> 旋转。
  • Windows:默认为 futex(无表),回退到定时退避 -> 旋转。
  • CUDA:默认为定时退避,回退到自旋。(这并不是在这棵树中全部签入的。)
  • 未识别的平台:默认为自旋。

  • 我想说的是_一个_实施。虽然它是_提案_的_实现_,但作为_C++2a 功能_,它是在 STL 实现中实现的。实际的实现可以更复杂(在 Windows 上有 CV 回退也很有用),也可以更复杂(此实现在通知 _futex_ 之前进行检查,但不是强制性的)。 (3认同)