C++ std::atomic和std::condition_变量wait,notify_*方法之间的差异

C++ std::atomic和std::condition_变量wait,notify_*方法之间的差异,c++,c++20,condition-variable,stdatomic,C++,C++20,Condition Variable,Stdatomic,我在浏览“原子操作库”时发现了一个新的c++20特性,即原子的“等待”和“通知”方法。我很好奇std::condition_变量的“wait”和“notify_”方法有什么区别。std:atomicwait,notify_all和notify_one方法与条件变量的方法类似。通过使用效率更高、更轻量级的原子变量,它们允许实现以前需要条件变量的逻辑 wait函数阻塞线程,直到修改原子对象的值。它需要一个参数来与原子对象的值进行比较。它反复执行: 如果值相等,它会阻塞线程,直到notify_one

我在浏览“原子操作库”时发现了一个新的c++20特性,即原子的“等待”和“通知”方法。我很好奇std::condition_变量的“wait”和“notify_”方法有什么区别。

std:atomic
wait
notify_all
notify_one
方法与条件变量的方法类似。通过使用效率更高、更轻量级的原子变量,它们允许实现以前需要条件变量的逻辑

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

  • 如果值相等,它会阻塞线程,直到
    notify_one
    notify_all
    通知线程,或者线程被错误地解除阻塞
  • 否则,将返回
注意:
wait
仅在值已更改时保证返回,即使底层实现错误地解除阻塞也是如此


您可以在此处找到实现:

该战略是按平台选择的:

  • Linux:默认为futex(带表),回退至futex(无表)->CVs->定时回退->旋转
  • Mac:默认为CVs(表),回退到定时回退->旋转
  • Windows:默认为futex(无表),回退至定时回退->旋转
  • CUDA:默认为定时回退,回退为旋转。(此树中未全部签入。)
  • 不明平台:默认为旋转

    • 整个使用模式有所不同

      条件变量
      等待需要互斥锁。在通知之前,应使用相同的互斥锁:

      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();
      

      差异是由实现定义的。除了界面之外,可能根本没有区别。我假设原子版本将通过一个更轻量级的方案或其他什么来实现,或者相反,它可能会执行更多的旋转,或者在开始时执行任何操作。虽然它是提案的实现,但作为C++2a特性,它是在STL实现中实现的。真正的实现可能更复杂(在Windows上设置CV后备功能也很有用),也可能更少(此实现在通知futex之前进行检查,但不是强制性的)。
      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();
      
      condition.store(true);
      std::unique_lock<std::mutex> lock(mtx);
      lock.unlock();
      cv.notify_one();
      
      
      std::atomic<bool> condition;
      
      ...
      
      condition.wait(false);
      
      ...
      
      condition.store(true);
      condition.notify_one();