{"id":343458,"date":"2023-01-02T21:01:04","date_gmt":"2023-01-02T21:01:04","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=343458"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=343458","title":{"rendered":"<span>std::conditional_variable \u0438 std::atomic_flag \u0432 \u0421++20<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0438\u0434\u0435\u044f \u0441\u0442\u0430\u0442\u044c\u0438 &#8212; \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c <code>std::conditional_variable<\/code> \u0438 <code>std::atomic_flag::wait<\/code> \u0438\u0437 \u0421++20, \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f. <\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0432\u0441\u0442\u0430\u0435\u0442 \u0432\u043e\u043f\u0440\u043e\u0441 \u043e\u0431 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0438 \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f\/\u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u0442\u043e \u043e\u0434\u043d\u043e \u0438\u0437 \u043f\u0435\u0440\u0432\u044b\u0445 \u0447\u0442\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0443\u043c &#8212; \u044d\u0442\u043e <code>std::conditional_variable<\/code>. \u0421\u043e\u0433\u043b\u0430\u0441\u043d\u043e cppreference:<\/p>\n<blockquote>\n<p>The\u00a0<code>condition_variable<\/code>\u00a0class is a synchronization primitive used with a\u00a0<a href=\"https:\/\/en.cppreference.com\/w\/cpp\/thread\/mutex\" rel=\"noopener noreferrer nofollow\">std::mutex<\/a>\u00a0to block one or more threads until another thread both modifies a shared variable (the\u00a0<em>condition<\/em>) and notifies the\u00a0<code>condition_variable<\/code>.<\/p>\n<\/blockquote>\n<p>\u0442.\u0435. <code>condition_variable<\/code> &#8212; \u044d\u0442\u043e \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043f\u043e\u0432\u0435\u0440\u0445 <code>std::mutex<\/code> (\u0435\u0441\u043b\u0438 \u0431\u044b\u0442\u044c \u0442\u043e\u0447\u043d\u044b\u043c &#8212; \u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e <code>std::unique_lock<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043f\u043e\u0432\u0435\u0440\u0445<code>std::mutex<\/code>). \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438 \u043a\u0440\u0430\u0442\u043a\u043e \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<pre><code class=\"cpp\">class Example final { public: void produce() { { std::lock_guard lck(m_); update = true; } cv_.notify_one(); }  void consume() { std::unique_lock lck(m_); cv_.wait(lck, [this] { return update;}); if (update) { std::cout &lt;&lt; \"update: new message from producer\" &lt;&lt; std::endl; } } private: std::mutex m_; std::condition_variable cv_;  bool update{false}; };  int main() { Example example; auto produce_thread = std::thread(&amp;Example::produce, &amp;example); auto consume_thread = std::thread(&amp;Example::consume, &amp;example);  if (produce_thread.joinable()) produce_thread.join();  if (consume_thread.joinable()) consume_thread.join(); }<\/code><\/pre>\n<p>\u0412\u044b\u0432\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c:<\/p>\n<pre><code class=\"bash\">update: new message from producer  Process finished with exit code 0<\/code><\/pre>\n<p>\u0412\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e: \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f 2 \u043f\u043e\u0442\u043e\u043a\u0430, \u043e\u0434\u0438\u043d \u043f\u0438\u0448\u0435\u0442, \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435. <\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 produce(). \u0438 \u043f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u0443\u0432\u0438\u0434\u0438\u043c &#8212; \u044d\u0442\u043e <code>std::lock_guard<\/code>.<\/p>\n<h2>std::lock_guard<\/h2>\n<p>\u041d\u0430 (5) \u0441\u0442\u0440\u043e\u043a\u0435 \u043c\u044b \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c mutex c \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>std::lock_guard<\/code>. \u042d\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u0440 RAII. \u041c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0448\u0430\u0431\u043b\u043e\u043d, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0435\u0441\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b lock \u0438 unlock \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0432\u043d\u0443\u0442\u0440\u0438 non-const-\u0441\u0441\u044b\u043b\u043a\u0443. \u0418 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c lock\/unlock \u0432 ctor\/dtor. \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u043e \u043a\u0430\u043a delete.<\/p>\n<p>\u0412\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e.<\/p>\n<details class=\"spoiler\">\n<summary>\u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a std::lock_guard<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cpp\">template&lt;typename _Mutex>     class lock_guard     {     public:       typedef _Mutex mutex_type;        explicit lock_guard(mutex_type&amp; __m) : _M_device(__m)       { _M_device.lock(); }        lock_guard(mutex_type&amp; __m, adopt_lock_t) noexcept : _M_device(__m)       { } \/\/ calling thread owns mutex        ~lock_guard()       { _M_device.unlock(); }        lock_guard(const lock_guard&amp;) = delete;       lock_guard&amp; operator=(const lock_guard&amp;) = delete;      private:       mutex_type&amp;  _M_device;     };<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0415\u0441\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440:<\/p>\n<pre><code class=\"cpp\">lock_guard(mutex_type&amp; __m, adopt_lock_t)<\/code><\/pre>\n<p>\u042d\u0442\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 mutex, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u0432\u0441\u0435 \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f unlock. \u0422\u0430\u043a \u0432 \u0447\u0435\u043c \u0436\u0435 \u0434\u0435\u043b\u043e? <code>adopt_lock_t<\/code> \u043c\u043e\u0436\u043d\u043e \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0442\u0435\u0433\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 <code>lock_guard<\/code>, \u0447\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 mutex \u0443\u0436\u0435 \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d, \u043d\u043e \u0432 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u0435\u0433\u043e \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0434\u043e \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0442\u044c. \u0412\u0441\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0435\u0449\u0435 \u0431\u043e\u043b\u0435\u0435 \u044f\u0441\u043d\u044b\u043c, \u043a\u043e\u0433\u0434\u0430 \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043c \u0441 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u0433\u043e adopt (\u043f\u0440\u0438\u043d\u044f\u0442\u044c, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c). adopt_lock &#8212; \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443. <\/p>\n<p>\u0414\u043b\u044f \u0447\u0435\u0433\u043e \u043d\u0443\u0436\u0435\u043d <code>adopt_lock<\/code>?<\/p>\n<p>\u0414\u043e \u0421++17 \u0438 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f <code>std::scoped_lock<\/code> \u044d\u0442\u043e \u0431\u044b\u043b \u0441\u043f\u043e\u0441\u043e\u0431 \u0434\u043b\u044f \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 mutex \u0438  \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u0438\u0445 \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438 + exception safe.<\/p>\n<pre><code class=\"cpp\">std::mutex m1; std::mutex m2; \/\/ ... std::lock(m1, m2); std::lock_guard lck1(m1, std::adopt_lock); std::lock_guard lck2(m2, std::adopt_lock); \/\/ ...<\/code><\/pre>\n<hr\/>\n<p><code>lock_guard<\/code> \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435 produce. \u041f\u043e\u0434 \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c mutex \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435.  \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0430  (4) \u0438 (7) \u0441\u0442\u0440\u043e\u0447\u043a\u0430\u043c\u0438.  \u041d\u0443\u0436\u043d\u043e \u043b\u0438 \u043f\u043e\u0434 mutex \u0432\u043d\u043e\u0441\u0438\u0442\u044c <code>notify_one<\/code> &#8212; \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435. \u0441\u0430\u043c <code>notify_one()<\/code> \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 <code>wait<\/code>.<\/p>\n<p>\u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a consume() \u0438 \u0437\u0434\u0435\u0441\u044c \u043f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u043c\u044b \u0432\u0438\u0434\u0438\u043c &#8212; \u044d\u0442\u043e <code>std::unique_lock<\/code>.<\/p>\n<h2>std::unique_lock<\/h2>\n<p>\u041d\u0430 (12) \u0441\u0442\u0440\u043e\u043a\u0435 \u043c\u044b \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c mutex \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>std::unique_lock<\/code>. \u0418 \u044d\u0442\u043e \u0442\u043e\u0436\u0435 RAII. <\/p>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u044d\u0442\u043e\u0442 \u043b\u043e\u043a \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0441\u044b\u0440\u043e\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 mutex. \u041f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 <code>_M_owns<\/code> &#8212; \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f, \u043a\u0442\u043e \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u044d\u0442\u043e\u0439 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<pre><code class=\"cpp\">mutex_type*_M_device; bool_M_owns;<\/code><\/pre>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u044b \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430:<\/p>\n<pre><code class=\"cpp\">\/\/ ... explicit unique_lock(mutex_type&amp; __m)       : _M_device(std::__addressof(__m)), _M_owns(false)       { lock(); _M_owns = true;       } \/\/ ... void lock() { if (!_M_device)   __throw_system_error(int(errc::operation_not_permitted)); else if (_M_owns)   __throw_system_error(int(errc::resource_deadlock_would_occur)); else   {     _M_device->lock();     _M_owns = true;   } } \/\/ ...<\/code><\/pre>\n<p>\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0430\u0434\u0440\u0435\u0441 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u0433\u043e mutex \u0432 <code>_M_device<\/code> \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c <code>lock()<\/code>, \u0433\u0434\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u043c\u044b \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438. \u0421\u0442\u0440\u0430\u043d\u043d\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0447\u0442\u043e <code>_M_owns = true<\/code> \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d\u043e 2 \u0440\u0430\u0437\u0430. \u041d\u0443 \u0434\u0430 \u043b\u0430\u0434\u043d\u043e.<\/p>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440:<\/p>\n<pre><code class=\"cpp\">~unique_lock() { if (_M_owns)   unlock(); }<\/code><\/pre>\n<p><code>unlock()<\/code> \u0431\u0443\u0434\u0435\u043c \u0437\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438, \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0438 \u043e\u0442 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 <code>std::lock_guard<\/code>, \u0433\u0434\u0435 \u0432 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>unlock()<\/code>.<\/p>\n<p>\u0415\u0441\u0442\u044c \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0439 \u043d\u0430\u043c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0441\u043e \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u043c \u0442\u0435\u0433\u043e\u043c <code>adopt_lock<\/code>:<\/p>\n<pre><code class=\"cpp\">unique_lock(mutex_type&amp; __m, adopt_lock_t) noexcept       : _M_device(std::__addressof(__m)), _M_owns(true)       { \/\/ XXX calling thread owns mutex       }<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 mutex \u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c\u0441\u044f \u0435\u0433\u043e \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0435\u043c.<\/p>\n<p>\u041d\u043e \u0435\u0441\u0442\u044c \u0438 \u043d\u043e\u0432\u044b\u0435 \u0442\u0435\u0433\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <code>defer_lock<\/code>:<\/p>\n<pre><code class=\"cpp\">unique_lock(mutex_type&amp; __m, defer_lock_t) noexcept       : _M_device(std::__addressof(__m)), _M_owns(false)       { }<\/code><\/pre>\n<p>\u0421 \u0430\u043d\u0433\u043b. defer &#8212; \u043e\u0442\u043b\u043e\u0436\u0438\u0442\u044c \u0442.\u0435. \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043e\u0442\u043b\u043e\u0436\u0438\u0442\u044c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443. <\/p>\n<p>\u041d\u043e \u043a\u0442\u043e \u0442\u043e\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c mutex, \u0435\u0441\u043b\u0438 \u0432 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u043a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0435\u043b\u0438 <code>unlock()<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438, \u0430 \u0432 \u044d\u0442\u043e\u043c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 <code>_M_owns(false)<\/code>? <code>std::unique_lock<\/code> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043d\u0435\u0436\u0435\u043b\u0438 <code>std::lock_guard.<\/code> \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043c\u0435\u0442\u043e\u0434 lock()\/unlock(). \u0418 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 <code>unique_lock<\/code> \u0441  <code>defer_lock<\/code> \u043c\u043e\u0436\u043d\u043e \u0432\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0438 \u044d\u0442\u043e\u0442 <code>unique_lock<\/code> \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432 <code>std::lock<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0437\u043e\u0432\u0435\u0442 <code>lock()<\/code> \u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u044d\u0442\u043e\u0442 <code>unique_lock<\/code> \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0435\u043c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0435\u0441\u0442\u044c try_to_lock_t, duration \u043b\u043e\u0433\u0438\u043a\u0430, \u043d\u043e \u043d\u0430 \u043d\u0438\u0445 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0443.<\/p>\n<p>\u0413\u0434\u0435 \u044d\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c?<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u043e\u0442 \u0436\u0435 \u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0442\u043e \u0438 \u0443 <code>lock_guard<\/code> &#8212; \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 mutex \u0434\u043e \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f <code>std::scoped_lock<\/code>.<\/p>\n<pre><code class=\"cpp\">std::mutex m1; std::mutex m2; \/\/ ... std::unique_lock lck1(m1, std::defer_lock); std::unique_lock lck2(m2, std::defer_lock); std::lock(lck1, lck2);<\/code><\/pre>\n<hr\/>\n<p>\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u043c\u0435\u0442\u043e\u0434\u0443 consume() \u0438 \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u043e\u0447\u043a\u0443 (13). \u0414\u043e \u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f wait \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 mutex &#8212; \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438 <code>std::unique_lock<\/code>.<\/p>\n<h2>std::condition_variable::wait<\/h2>\n<p>\u0412 <code>wait<\/code> \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 <code>std::unique_lock<\/code>, <code>wait<\/code> \u0441\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 \u0438 \u0443\u0441\u044b\u043f\u0430\u0435\u0442 (\u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430: \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442 \u0432  wait \u0438\u0441\u0442\u0438\u043d\u043d\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0438 \u043d\u0435 \u0443\u0441\u043d\u0443\u0442\u044c). \u0427\u0435\u0440\u0435\u0437 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0442\u043e\u043a \u043f\u0440\u043e\u0441\u044b\u043f\u0430\u0435\u0442\u0441\u044f \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443. \u0418\u043c\u0435\u043d\u043d\u043e \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c lock\/unlock \u0437\u0434\u0435\u0441\u044c \u043d\u0435\u043b\u044c\u0437\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>std::lock_guard<\/code> &#8212; \u0443 \u043d\u0435\u0433\u043e \u043f\u043e\u043f\u0440\u043e\u0441\u0442\u0443 \u043d\u0435\u0442 \u0442\u0430\u043a\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u043f\u0440\u043e \u043f\u0440\u043e\u0431\u0443\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u0430 \u043d\u0430 <code>wait<\/code>. \u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u043f\u0440\u043e\u0431\u0443\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u0430:<\/p>\n<ul>\n<li>\n<p><code>notify_one()\/notify_all()<\/code>: \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0438 wait \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442. \u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441 \u0443\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435\u043c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438 \u043f\u0440\u0438 notify_*. \u0414\u043b\u044f \u0432\u0441\u0435\u0445 mutex \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 \u043d\u0435 \u0434\u043e\u043b\u044c\u0448\u0435 \u0447\u0435\u043c \u043d\u0443\u0436\u043d\u043e. \u0412 \u043c\u043e\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u044d\u0442\u043e \u0434\u043e (6) \u0441\u0442\u0440\u043e\u0447\u043a\u0438 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e. \u041d\u043e \u043a\u0430\u043a \u0431\u044b\u0442\u044c \u0441 notify? \u041e\u0442\u0432\u0435\u0442 \u043a\u0430\u043a \u0432\u0441\u0435\u0433\u0434\u0430 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438: <\/p>\n<blockquote>\n<p>The notifying thread does not need to hold the lock on the same mutex as the one held by the waiting thread(s); in fact doing so is a pessimization, since the notified thread would immediately block again, waiting for the notifying thread to release the lock. However, some implementations (in particular many implementations of pthreads) recognize this situation and avoid this &#171;hurry up and wait&#187; scenario by transferring the waiting thread from the condition variable&#8217;s queue directly to the queue of the mutex within the notify call, without waking it up.<\/p>\n<p>Notifying while under the lock may nevertheless be necessary when precise scheduling of events is required, e.g. if the waiting thread would exit the program if the condition is satisfied, causing destruction of the notifying thread&#8217;s condition variable. A spurious wakeup after mutex unlock but before notify would result in notify called on a destroyed object.<\/p>\n<\/blockquote>\n<\/li>\n<li>\n<p>spurious wakeup: \u043e\u043d\u0438 \u0436\u0435 \u043b\u043e\u0436\u043d\u044b\u0435 \u043f\u0440\u043e\u0431\u0443\u0436\u0434\u0435\u043d\u0438\u044f. \u041e\u043d\u0438 \u0435\u0441\u0442\u044c, \u043d\u043e \u043c\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0447\u0438\u043d\u044b \u0438\u0445 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f\/\u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u043b \u0440\u0430\u0437\u043d\u044b\u0435. \u0415\u0441\u0442\u044c \u0442\u0430\u043a\u043e\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u0435 &#8212; \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u0442\u043e\u043a \u043f\u0440\u043e\u0441\u044b\u043f\u0430\u0435\u0442\u0441\u044f, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0437\u044f\u0442\u044c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 &#8212; \u0432\u044b\u0437\u0432\u0430\u0432 syscall. \u041c\u0435\u0436\u0434\u0443 \u043f\u0440\u043e\u0431\u0443\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0438 \u0432\u044b\u0437\u043e\u0432\u043e\u043c syscall \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0432\u0440\u0435\u043c\u044f &#8212; \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0417\u0430 \u044d\u0442\u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043c\u043e\u0436\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0430\u0441 \u043f\u0440\u043e\u0431\u0443\u0434\u0438\u043b\u043e \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043b\u043e \u0431\u044b\u0442\u044c \u0438\u0441\u0442\u0438\u043d\u043d\u044b\u043c). \u0418 \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043b\u043e\u0436\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0441\u043b\u0435 wait \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e\u0442 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0438\u0441\u0442\u0438\u043d\u043d\u043e\u0441\u0442\u044c \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u043f\u0440\u043e\u0431\u0443\u0436\u0434\u0435\u043d\u0438\u044f. \u0415\u0441\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u0441\u0442\u0430\u0440\u043e\u0435 <a href=\"https:\/\/groups.google.com\/g\/comp.programming.threads\/c\/MnlYxCfql4w?hl=de&amp;pli=1\" rel=\"noopener noreferrer nofollow\">\u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435<\/a>. <\/p>\n<\/li>\n<li>\n<p>\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 <code>std::conditional_variable_any<\/code>, <code>wait_for<\/code> &#8230; &#8212; \u0442\u0443\u0442 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0443.<\/p>\n<\/li>\n<\/ul>\n<h2>std::atomic_flag<\/h2>\n<p><code>std::atomic_flag<\/code> &#8212; \u044d\u0442\u043e \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u044b\u0439 \u0442\u0438\u043f, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u0441\u043e\u0431\u043e\u0439 \u0431\u0443\u043b\u0435\u0432 \u0444\u043b\u0430\u0433. \u041e\u0431\u044a\u0435\u043a\u0442\u044b \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430  \u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u0438\u0437 2-\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439: \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0438\u043b\u0438 \u0441\u0431\u0440\u043e\u0448\u0435\u043d. \u0412 \u0421++20 \u0443 \u043d\u0435\u0433\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u043e\u0432\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b: <code>wait()<\/code>, <code>notify_*()<\/code>. \u0418 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0432 \u0441\u0430\u043c\u044b\u0445 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f\u0445 &#8212; \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0444\u043b\u0430\u0433\u0430, \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043e\u0439 \u0434\u043b\u044f <code>std::conditional_variable<\/code>.<\/p>\n<p>\u041d\u0430\u0431\u0440\u043e\u0441\u0430\u044e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0433\u0440\u044b \u043f\u0438\u043d\u0433-\u043f\u043e\u043d\u0433\u0430 (\u043f\u043e\u043b\u043d\u043e\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438: <a href=\"https:\/\/github.com\/k-morozov\/habr_atomic_cv\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/a>):<\/p>\n<p>\u0412\u0435\u0440\u0441\u0438\u044f \u0441 <code>conditional_variable<\/code>:<\/p>\n<pre><code class=\"cpp\">void game_cv::ping() { int counter = 0;  while (counter &lt;= MaxCountTimes) { { std::unique_lock lck(m_); cv_.wait(lck, [this]() { return ping_done_; }); ping_done_ = false; pong_done_ = true; counter++; } cv_.notify_one(); } }  void game_cv::pong() { int counter = 0;  while (counter&lt;MaxCountTimes) { { std::unique_lock lck(m_); cv_.wait(lck, [this](){ return pong_done_; }); ping_done_ = true; pong_done_ = false; counter++; } cv_.notify_one(); } }  void game_cv::start_game() { { std::unique_lock lck(m_); ping_done_ = true; } cv_.notify_one(); }<\/code><\/pre>\n<p>\u0412\u0435\u0440\u0441\u0438\u044f \u0441 <code>atomic_flag<\/code>:<\/p>\n<pre><code class=\"cpp\">void game_atomic::ping() { int counter = 0;  while (counter &lt;= MaxCountTimes) { pass_.wait(false); pass_.clear(); counter++; current_counter_++; pass_.notify_one(); } }  void game_atomic::pong() { int counter = 0;  while (counter &lt; MaxCountTimes) { pass_.wait(true);  pass_.test_and_set(); counter++; pass_.notify_one(); } }  void game_atomic::start_game() { pass_.test_and_set(); pass_.notify_one(); }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0437\u0430\u043c\u0435\u0440\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438:<\/p>\n<pre><code class=\"cpp\">auto start = std::chrono::system_clock::now();  game_->run();  std::chrono::duration&lt;double> dur = std::chrono::system_clock::now() - start; std::cout &lt;&lt; \"Duration: \" &lt;&lt; dur.count() &lt;&lt; \" seconds\" &lt;&lt; std::endl;<\/code><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0437\u0430\u043c\u0435\u0440\u043e\u0432:<\/p>\n<p>\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043c\u0435\u0440: \u041e\u0421: ubuntu 22.04, CPU: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz RAM: 32 \u0413\u0431<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td data-colwidth=\"225\" width=\"225\">\n<p align=\"left\">\n<\/td>\n<td data-colwidth=\"234\" width=\"234\">\n<p align=\"left\">clang-14 release<\/p>\n<\/td>\n<td>\n<p align=\"left\">gcc-11 release<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"225\" width=\"225\">\n<p>\u0432\u0435\u0440\u0441\u0438\u044f \u0441 conditional_variable<\/p>\n<\/td>\n<td data-colwidth=\"234\" width=\"234\">\n<p align=\"left\">4.0581 &#8212; 4.29326 &#8212; 4.15922 seconds<\/p>\n<\/td>\n<td>\n<p align=\"left\">4.15656 &#8212; 3.96363 &#8212; 3.94372 seconds<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"225\" width=\"225\">\n<p align=\"left\">\u0432\u0435\u0440\u0441\u0438\u044f \u0441 atomic_flag<\/p>\n<\/td>\n<td data-colwidth=\"234\" width=\"234\">\n<p align=\"left\">0.250251 &#8212; 0.24626 &#8212; 0.23954 seconds<\/p>\n<\/td>\n<td>\n<p align=\"left\">0.263211- 3.96363 &#8212; 0.260344 seconds<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0417\u0430\u043c\u0435\u0440 \u0432 CI: \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/github.com\/k-morozov\/habr_atomic_cv\/actions\/runs\/3817973907\/jobs\/6494568466\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a><\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u043b \u0437\u0430\u043c\u0435\u0440\u044b \u043d\u0430 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u0432 cloud: \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043e\u043f\u0438\u0441\u0430\u043b \u0432 readme <a href=\"https:\/\/github.com\/k-morozov\/habr_atomic_cv\" rel=\"noopener noreferrer nofollow\">\u0441\u0441\u044b\u043b\u043a\u0430<\/a><\/p>\n<\/p>\n<p>\u041d\u043e\u0432\u044b\u0439 <code>wait<\/code> \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u0435\u0439 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043e\u0439 \u0434\u043b\u044f <code>std::conditional_variable<\/code>, \u043a\u043e\u0433\u0434\u0430 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442 &#8212; \u0431\u043e\u043d\u0443\u0441\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0448\u0443\u0441\u0442\u0440\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p> <!----> <!----><\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/708918\/\"> https:\/\/habr.com\/ru\/post\/708918\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0438\u0434\u0435\u044f \u0441\u0442\u0430\u0442\u044c\u0438 &#8212; \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c <code>std::conditional_variable<\/code> \u0438 <code>std::atomic_flag::wait<\/code> \u0438\u0437 \u0421++20, \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f. <\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0432\u0441\u0442\u0430\u0435\u0442 \u0432\u043e\u043f\u0440\u043e\u0441 \u043e\u0431 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0438 \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f\/\u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u0442\u043e \u043e\u0434\u043d\u043e \u0438\u0437 \u043f\u0435\u0440\u0432\u044b\u0445 \u0447\u0442\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0443\u043c &#8212; \u044d\u0442\u043e <code>std::conditional_variable<\/code>. \u0421\u043e\u0433\u043b\u0430\u0441\u043d\u043e cppreference:<\/p>\n<blockquote>\n<p>The\u00a0<code>condition_variable<\/code>\u00a0class is a synchronization primitive used with a\u00a0<a href=\"https:\/\/en.cppreference.com\/w\/cpp\/thread\/mutex\" rel=\"noopener noreferrer nofollow\">std::mutex<\/a>\u00a0to block one or more threads until another thread both modifies a shared variable (the\u00a0<em>condition<\/em>) and notifies the\u00a0<code>condition_variable<\/code>.<\/p>\n<\/blockquote>\n<p>\u0442.\u0435. <code>condition_variable<\/code> &#8212; \u044d\u0442\u043e \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043f\u043e\u0432\u0435\u0440\u0445 <code>std::mutex<\/code> (\u0435\u0441\u043b\u0438 \u0431\u044b\u0442\u044c \u0442\u043e\u0447\u043d\u044b\u043c &#8212; \u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e <code>std::unique_lock<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043f\u043e\u0432\u0435\u0440\u0445<code>std::mutex<\/code>). \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438 \u043a\u0440\u0430\u0442\u043a\u043e \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<pre><code class=\"cpp\">class Example final { public: void produce() { { std::lock_guard lck(m_); update = true; } cv_.notify_one(); }  void consume() { std::unique_lock lck(m_); cv_.wait(lck, [this] { return update;}); if (update) { std::cout &lt;&lt; \"update: new message from producer\" &lt;&lt; std::endl; } } private: std::mutex m_; std::condition_variable cv_;  bool update{false}; };  int main() { Example example; auto produce_thread = std::thread(&amp;Example::produce, &amp;example); auto consume_thread = std::thread(&amp;Example::consume, &amp;example);  if (produce_thread.joinable()) produce_thread.join();  if (consume_thread.joinable()) consume_thread.join(); }<\/code><\/pre>\n<p>\u0412\u044b\u0432\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c:<\/p>\n<pre><code class=\"bash\">update: new message from producer  Process finished with exit code 0<\/code><\/pre>\n<p>\u0412\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e: \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f 2 \u043f\u043e\u0442\u043e\u043a\u0430, \u043e\u0434\u0438\u043d \u043f\u0438\u0448\u0435\u0442, \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435. <\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 produce(). \u0438 \u043f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u0443\u0432\u0438\u0434\u0438\u043c &#8212; \u044d\u0442\u043e <code>std::lock_guard<\/code>.<\/p>\n<h2>std::lock_guard<\/h2>\n<p>\u041d\u0430 (5) \u0441\u0442\u0440\u043e\u043a\u0435 \u043c\u044b \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c mutex c \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>std::lock_guard<\/code>. \u042d\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u0440 RAII. \u041c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0448\u0430\u0431\u043b\u043e\u043d, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0435\u0441\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b lock \u0438 unlock \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0432\u043d\u0443\u0442\u0440\u0438 non-const-\u0441\u0441\u044b\u043b\u043a\u0443. \u0418 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c lock\/unlock \u0432 ctor\/dtor. \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u043e \u043a\u0430\u043a delete.<\/p>\n<p>\u0412\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e.<\/p>\n<details class=\"spoiler\">\n<summary>\u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a std::lock_guard<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cpp\">template&lt;typename _Mutex>     class lock_guard     {     public:       typedef _Mutex mutex_type;        explicit lock_guard(mutex_type&amp; __m) : _M_device(__m)       { _M_device.lock(); }        lock_guard(mutex_type&amp; __m, adopt_lock_t) noexcept : _M_device(__m)       { } \/\/ calling thread owns mutex        ~lock_guard()       { _M_device.unlock(); }        lock_guard(const lock_guard&amp;) = delete;       lock_guard&amp; operator=(const lock_guard&amp;) = delete;      private:       mutex_type&amp;  _M_device;     };<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0415\u0441\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440:<\/p>\n<pre><code class=\"cpp\">lock_guard(mutex_type&amp; __m, adopt_lock_t)<\/code><\/pre>\n<p>\u042d\u0442\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 mutex, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u0432\u0441\u0435 \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f unlock. \u0422\u0430\u043a \u0432 \u0447\u0435\u043c \u0436\u0435 \u0434\u0435\u043b\u043e? <code>adopt_lock_t<\/code> \u043c\u043e\u0436\u043d\u043e \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0442\u0435\u0433\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 <code>lock_guard<\/code>, \u0447\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 mutex \u0443\u0436\u0435 \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d, \u043d\u043e \u0432 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u0435\u0433\u043e \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0434\u043e \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0442\u044c. \u0412\u0441\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0435\u0449\u0435 \u0431\u043e\u043b\u0435\u0435 \u044f\u0441\u043d\u044b\u043c, \u043a\u043e\u0433\u0434\u0430 \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043c \u0441 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u0433\u043e adopt (\u043f\u0440\u0438\u043d\u044f\u0442\u044c, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c). adopt_lock &#8212; \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443. <\/p>\n<p>\u0414\u043b\u044f \u0447\u0435\u0433\u043e \u043d\u0443\u0436\u0435\u043d <code>adopt_lock<\/code>?<\/p>\n<p>\u0414\u043e \u0421++17 \u0438 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f <code>std::scoped_lock<\/code> \u044d\u0442\u043e \u0431\u044b\u043b \u0441\u043f\u043e\u0441\u043e\u0431 \u0434\u043b\u044f \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 mutex \u0438  \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u0438\u0445 \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438 + exception safe.<\/p>\n<pre><code class=\"cpp\">std::mutex m1; std::mutex m2; \/\/ ... std::lock(m1, m2); std::lock_guard lck1(m1, std::adopt_lock); std::lock_guard lck2(m2, std::adopt_lock); \/\/ ...<\/code><\/pre>\n<hr\/>\n<p><code>lock_guard<\/code> \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435 produce. \u041f\u043e\u0434 \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c mutex \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435.  \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0430  (4) \u0438 (7) \u0441\u0442\u0440\u043e\u0447\u043a\u0430\u043c\u0438.  \u041d\u0443\u0436\u043d\u043e \u043b\u0438 \u043f\u043e\u0434 mutex \u0432\u043d\u043e\u0441\u0438\u0442\u044c <code>notify_one<\/code> &#8212; \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435. \u0441\u0430\u043c <code>notify_one()<\/code> \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 <code>wait<\/code>.<\/p>\n<p>\u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a consume() \u0438 \u0437\u0434\u0435\u0441\u044c \u043f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u043c\u044b \u0432\u0438\u0434\u0438\u043c &#8212; \u044d\u0442\u043e <code>std::unique_lock<\/code>.<\/p>\n<h2>std::unique_lock<\/h2>\n<p>\u041d\u0430 (12) \u0441\u0442\u0440\u043e\u043a\u0435 \u043c\u044b \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u043c mutex \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>std::unique_lock<\/code>. \u0418 \u044d\u0442\u043e \u0442\u043e\u0436\u0435 RAII. <\/p>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u044d\u0442\u043e\u0442 \u043b\u043e\u043a \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0441\u044b\u0440\u043e\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 mutex. \u041f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 <code>_M_owns<\/code> &#8212; \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f, \u043a\u0442\u043e \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u044d\u0442\u043e\u0439 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<pre><code class=\"cpp\">mutex_type*_M_device; bool_M_owns;<\/code><\/pre>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u044b \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430:<\/p>\n<pre><code class=\"cpp\">\/\/ ... explicit unique_lock(mutex_type&amp; __m)       : _M_device(std::__addressof(__m)), _M_owns(false)       { lock(); _M_owns = true;       } \/\/ ... void lock() { if (!_M_device)   __throw_system_error(int(errc::operation_not_permitted)); else if (_M_owns)   __throw_system_error(int(errc::resource_deadlock_would_occur)); else   {     _M_device->lock();     _M_owns = true;   } } \/\/ ...<\/code><\/pre>\n<p>\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0430\u0434\u0440\u0435\u0441 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u0433\u043e mutex \u0432 <code>_M_device<\/code> \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c <code>lock()<\/code>, \u0433\u0434\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u043c\u044b \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438. \u0421\u0442\u0440\u0430\u043d\u043d\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0447\u0442\u043e <code>_M_owns = true<\/code> \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d\u043e 2 \u0440\u0430\u0437\u0430. \u041d\u0443 \u0434\u0430 \u043b\u0430\u0434\u043d\u043e.<\/p>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440:<\/p>\n<pre><code class=\"cpp\">~unique_lock() { if (_M_owns)   unlock(); }<\/code><\/pre>\n<p><code>unlock()<\/code> \u0431\u0443\u0434\u0435\u043c \u0437\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438, \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0438 \u043e\u0442 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 <code>std::lock_guard<\/code>, \u0433\u0434\u0435 \u0432 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>unlock()<\/code>.<\/p>\n<p>\u0415\u0441\u0442\u044c \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0439 \u043d\u0430\u043c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0441\u043e \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u043c \u0442\u0435\u0433\u043e\u043c <code>adopt_lock<\/code>:<\/p>\n<pre><code class=\"cpp\">unique_lock(mutex_type&amp; __m, adopt_lock_t) noexcept       : _M_device(std::__addressof(__m)), _M_owns(true)       { \/\/ XXX calling thread owns mutex       }<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 mutex \u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c\u0441\u044f \u0435\u0433\u043e \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0435\u043c.<\/p>\n<p>\u041d\u043e \u0435\u0441\u0442\u044c \u0438 \u043d\u043e\u0432\u044b\u0435 \u0442\u0435\u0433\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <code>defer_lock<\/code>:<\/p>\n<pre><code class=\"cpp\">unique_lock(mutex_type&amp; __m, defer_lock_t) noexcept       : _M_device(std::__addressof(__m)), _M_owns(false)       { }<\/code><\/pre>\n<p>\u0421 \u0430\u043d\u0433\u043b. defer &#8212; \u043e\u0442\u043b\u043e\u0436\u0438\u0442\u044c \u0442.\u0435. \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043e\u0442\u043b\u043e\u0436\u0438\u0442\u044c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443. <\/p>\n<p>\u041d\u043e \u043a\u0442\u043e \u0442\u043e\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c mutex, \u0435\u0441\u043b\u0438 \u0432 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u043a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0435\u043b\u0438 <code>unlock()<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438, \u0430 \u0432 \u044d\u0442\u043e\u043c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 <code>_M_owns(false)<\/code>? <code>std::unique_lock<\/code> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043d\u0435\u0436\u0435\u043b\u0438 <code>std::lock_guard.<\/code> \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043c\u0435\u0442\u043e\u0434 lock()\/unlock(). \u0418 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 <code>unique_lock<\/code> \u0441  <code>defer_lock<\/code> \u043c\u043e\u0436\u043d\u043e \u0432\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0438 \u044d\u0442\u043e\u0442 <code>unique_lock<\/code> \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432 <code>std::lock<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0437\u043e\u0432\u0435\u0442 <code>lock()<\/code> \u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u044d\u0442\u043e\u0442 <code>unique_lock<\/code> \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0435\u043c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0435\u0441\u0442\u044c try_to_lock_t, duration \u043b\u043e\u0433\u0438\u043a\u0430, \u043d\u043e \u043d\u0430 \u043d\u0438\u0445 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0443.<\/p>\n<p>\u0413\u0434\u0435 \u044d\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c?<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u043e\u0442 \u0436\u0435 \u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0442\u043e \u0438 \u0443 <code>lock_guard<\/code> &#8212; \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 mutex \u0434\u043e \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f <code>std::scoped_lock<\/code>.<\/p>\n<pre><code class=\"cpp\">std::mutex m1; std::mutex m2; \/\/ ... std::unique_lock lck1(m1, std::defer_lock); std::unique_lock lck2(m2, std::defer_lock); std::lock(lck1, lck2);<\/code><\/pre>\n<hr\/>\n<p>\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u043c\u0435\u0442\u043e\u0434\u0443 consume() \u0438 \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u043e\u0447\u043a\u0443 (13). \u0414\u043e \u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f wait \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 mutex &#8212; \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438 <code>std::unique_lock<\/code>.<\/p>\n<h2>std::condition_variable::wait<\/h2>\n<p>\u0412 <code>wait<\/code> \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 <code>std::unique_lock<\/code>, <code>wait<\/code> \u0441\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 \u0438 \u0443\u0441\u044b\u043f\u0430\u0435\u0442 (\u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430: \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442 \u0432  wait \u0438\u0441\u0442\u0438\u043d\u043d\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0438 \u043d\u0435 \u0443\u0441\u043d\u0443\u0442\u044c). \u0427\u0435\u0440\u0435\u0437 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0442\u043e\u043a \u043f\u0440\u043e\u0441\u044b\u043f\u0430\u0435\u0442\u0441\u044f \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443. \u0418\u043c\u0435\u043d\u043d\u043e \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c lock\/unlock \u0437\u0434\u0435\u0441\u044c \u043d\u0435\u043b\u044c\u0437\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>std::lock_guard<\/code> &#8212; \u0443 \u043d\u0435\u0433\u043e \u043f\u043e\u043f\u0440\u043e\u0441\u0442\u0443 \u043d\u0435\u0442 \u0442\u0430\u043a\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u043f\u0440\u043e \u043f\u0440\u043e\u0431\u0443\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u0430 \u043d\u0430 <code>wait<\/code>. \u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u043f\u0440\u043e\u0431\u0443\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u0430:<\/p>\n<ul>\n<li>\n<p><code>notify_one()\/notify_all()<\/code>: \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0438 wait \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442. \u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441 \u0443\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435\u043c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438 \u043f\u0440\u0438 notify_*. \u0414\u043b\u044f \u0432\u0441\u0435\u0445 mutex \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 \u043d\u0435 \u0434\u043e\u043b\u044c\u0448\u0435 \u0447\u0435\u043c \u043d\u0443\u0436\u043d\u043e. \u0412 \u043c\u043e\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u044d\u0442\u043e \u0434\u043e (6) \u0441\u0442\u0440\u043e\u0447\u043a\u0438 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e. \u041d\u043e \u043a\u0430\u043a \u0431\u044b\u0442\u044c \u0441 notify? \u041e\u0442\u0432\u0435\u0442 \u043a\u0430\u043a \u0432\u0441\u0435\u0433\u0434\u0430 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438: <\/p>\n<blockquote>\n<p>The notifying thread does not need to hold the lock on the same mutex as the one held by the waiting thread(s); in fact doing so is a pessimization, since the notified thread would immediately block again, waiting for the notifying thread to release the lock. However, some implementations (in particular many implementations of pthreads) recognize this situation and avoid this &#171;hurry up and wait&#187; scenario by transferring the waiting thread from the condition variable&#8217;s queue directly to the queue of the mutex within the notify call, without waking it up.<\/p>\n<p>Notifying while under the lock may nevertheless be necessary when precise scheduling of events is required, e.g. if the waiting thread would exit the program if the condition is satisfied, causing destruction of the notifying thread&#8217;s condition variable. A spurious wakeup after mutex unlock but before notify would result in notify called on a destroyed object.<\/p>\n<\/blockquote>\n<\/li>\n<li>\n<p>spurious wakeup: \u043e\u043d\u0438 \u0436\u0435 \u043b\u043e\u0436\u043d\u044b\u0435 \u043f\u0440\u043e\u0431\u0443\u0436\u0434\u0435\u043d\u0438\u044f. \u041e\u043d\u0438 \u0435\u0441\u0442\u044c, \u043d\u043e \u043c\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0447\u0438\u043d\u044b \u0438\u0445 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f\/\u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u043b \u0440\u0430\u0437\u043d\u044b\u0435. \u0415\u0441\u0442\u044c \u0442\u0430\u043a\u043e\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u0435 &#8212; \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u0442\u043e\u043a \u043f\u0440\u043e\u0441\u044b\u043f\u0430\u0435\u0442\u0441\u044f, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0437\u044f\u0442\u044c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 &#8212; \u0432\u044b\u0437\u0432\u0430\u0432 syscall. \u041c\u0435\u0436\u0434\u0443 \u043f\u0440\u043e\u0431\u0443\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0438 \u0432\u044b\u0437\u043e\u0432\u043e\u043c syscall \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0432\u0440\u0435\u043c\u044f &#8212; \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0417\u0430 \u044d\u0442\u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043c\u043e\u0436\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0430\u0441 \u043f\u0440\u043e\u0431\u0443\u0434\u0438\u043b\u043e \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043b\u043e \u0431\u044b\u0442\u044c \u0438\u0441\u0442\u0438\u043d\u043d\u044b\u043c). \u0418 \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043b\u043e\u0436\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0441\u043b\u0435 wait \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e\u0442 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0438\u0441\u0442\u0438\u043d\u043d\u043e\u0441\u0442\u044c \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u043f\u0440\u043e\u0431\u0443\u0436\u0434\u0435\u043d\u0438\u044f. \u0415\u0441\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u0441\u0442\u0430\u0440\u043e\u0435 <a href=\"https:\/\/groups.google.com\/g\/comp.programming.threads\/c\/MnlYxCfql4w?hl=de&amp;pli=1\" rel=\"noopener noreferrer nofollow\">\u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435<\/a>. <\/p>\n<\/li>\n<li>\n<p>\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 <code>std::conditional_variable_any<\/code>, <code>wait_for<\/code> &#8230; &#8212; \u0442\u0443\u0442 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0443.<\/p>\n<\/li>\n<\/ul>\n<h2>std::atomic_flag<\/h2>\n<p><code>std::atomic_flag<\/code> &#8212; \u044d\u0442\u043e \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u044b\u0439 \u0442\u0438\u043f, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u0441\u043e\u0431\u043e\u0439 \u0431\u0443\u043b\u0435\u0432 \u0444\u043b\u0430\u0433. \u041e\u0431\u044a\u0435\u043a\u0442\u044b \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430  \u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u0438\u0437 2-\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439: \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0438\u043b\u0438 \u0441\u0431\u0440\u043e\u0448\u0435\u043d. \u0412 \u0421++20 \u0443 \u043d\u0435\u0433\u043e \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u043e\u0432\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b: <code>wait()<\/code>, <code>notify_*()<\/code>. \u0418 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0432 \u0441\u0430\u043c\u044b\u0445 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f\u0445 &#8212; \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0444\u043b\u0430\u0433\u0430, \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043e\u0439 \u0434\u043b\u044f <code>std::conditional_variable<\/code>.<\/p>\n<p>\u041d\u0430\u0431\u0440\u043e\u0441\u0430\u044e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0433\u0440\u044b \u043f\u0438\u043d\u0433-\u043f\u043e\u043d\u0433\u0430 (\u043f\u043e\u043b\u043d\u043e\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438: <a href=\"https:\/\/github.com\/k-morozov\/habr_atomic_cv\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/a>):<\/p>\n<p>\u0412\u0435\u0440\u0441\u0438\u044f \u0441 <code>conditional_variable<\/code>:<\/p>\n<pre><code class=\"cpp\">void game_cv::ping() { int counter = 0;  while (counter &lt;= MaxCountTimes) { { std::unique_lock lck(m_); cv_.wait(lck, [this]() { return ping_done_; }); ping_done_ = false; pong_done_ = true; counter++; } cv_.notify_one(); } }  void game_cv::pong() { int counter = 0;  while (counter&lt;MaxCountTimes) { { std::unique_lock lck(m_); cv_.wait(lck, [this](){ return pong_done_; }); ping_done_ = true; pong_done_ = false; counter++; } cv_.notify_one(); } }  void game_cv::start_game() { { std::unique_lock lck(m_); ping_done_ = true; } cv_.notify_one(); }<\/code><\/pre>\n<p>\u0412\u0435\u0440\u0441\u0438\u044f \u0441 <code>atomic_flag<\/code>:<\/p>\n<pre><code class=\"cpp\">void game_atomic::ping() { int counter = 0;  while (counter &lt;= MaxCountTimes) { pass_.wait(false); pass_.clear(); counter++; current_counter_++; pass_.notify_one(); } }  void game_atomic::pong() { int counter = 0;  while (counter &lt; MaxCountTimes) { pass_.wait(true);  pass_.test_and_set(); counter++; pass_.notify_one(); } }  void game_atomic::start_game() { pass_.test_and_set(); pass_.notify_one(); }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0437\u0430\u043c\u0435\u0440\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438:<\/p>\n<pre><code class=\"cpp\">auto start =<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-343458","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/343458","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=343458"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/343458\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=343458"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=343458"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=343458"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}