簡體   English   中英

condition_variable::notify_one 不會立即解除阻塞等待?

[英]condition_variable::notify_one does not instantly unblock wait?

我有一個關於 notify_one 函數的問題。 在以下代碼中,

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>
#include <mutex>

std::condition_variable cv;
std::mutex m;
bool ready = false;

void f()
{
  std::unique_lock<std::mutex> lk(m);
  std::cout << "get into wait, ready=" << ready << std::endl;
  cv.wait(lk, []() { return ready; });
  std::cout << "get out of wait, ready=" << ready << std::endl;
}

int main()
{
  std::thread a(f);

  std::this_thread::sleep_for(std::chrono::seconds(1));

  {
    std::unique_lock<std::mutex> lk(m, std::defer_lock);
    if (lk.try_lock()) {
      std::cout << "main try_lock success, ready=" << ready << std::endl;
      ready = true;
    }
  }
  std::cout << "main notify, ready=" << ready << std::endl;
  cv.notify_one();

  // std::cout << "hello" << std::endl;

  {
    std::unique_lock<std::mutex> lk(m, std::defer_lock);
    if (lk.try_lock()) {
      std::cout << "main try_lock success, ready=" << ready << std::endl;
      ready = true;
    }
  }
  std::cout << "main notify, ready=" << ready << std::endl;
  cv.notify_one();

  a.join();

  return 0;
}

我得到以下結果,

get into wait, ready=0
main try_lock success, ready=0
main notify, ready=1
main try_lock success, ready=1
main notify, ready=1
get out of wait, ready=1

但我希望得到以下結果,因為根據page ,如果調用 notify_one ,則等待解鎖並重新獲取 mutex(m) 的鎖定。

get into wait, ready=0
main try_lock success, ready=0
main notify, ready=1
main notify, ready=1
get out of wait, ready=1

我發現如果我注釋掉std::cout << "hello" << std::endl; 我得到了預期的結果。 在我看來,notify_one 不會立即解除等待。 它是正確的?

非常感謝!

在我看來,notify_one 不會立即解除等待。 它是正確的?

通知立即解除等待,這意味着等待能夠在通知后恢復。 也就是說,休眠線程被標記為可運行。

但是,調度程序不一定會立即重新啟動它。 如果它必須搶占一些已經運行的線程/進程,它可能會等待直到產生、系統調用或其他一些取消點,否則在當前時間片結束之前甚至不會查看新運行的線程。

解除阻塞與強制立即進行上下文切換不同(這是幸運的,否則同步會更加昂貴)。

在你的第一個cv.notify_one(); 您沒有同步點(直到a.join(); )並且已經運行的線程很可能會繼續運行並到達a.join(); 在調度程序決定讓另一個線程旋轉之前。

作為實驗,您可以通過在通知后稍作休眠來讓出線程的執行槽——這可能會導致輸出的順序與您預期的一樣。

cv.notify_one();
std::this_thread::sleep_for(std::chrono::milliseconds(1));

但是不要在生產代碼中依賴它。 這不能保證任何事情,因為線程之間沒有同步(除了join() )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM