producer()有人可以解釋為什么當睡眠呼叫未注釋時此代碼無法按預期作業?如果將 sleep 呼叫移出unique_lock.
澄清:按預期作業:producer()創建存盤在data這些訊息中的新訊息,然后由consumer(). 取消注釋 sleep 呼叫時會發生什么:不產生輸出。我希望以 1 秒的間隔生成和列印新訊息。
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <ratio>
#include <string>
#include <thread>
#include <queue>
std::string data;
std::atomic<bool> ready;
std::condition_variable cv;
std::mutex m;
void producer()
{
int c{};
while (true)
{
c;
{
std::unique_lock<std::mutex> lock{ m };
data = "count: " std::to_string(c);
// std::this_thread::sleep_for(std::chrono::seconds{ 1 }); // THIS LINE
ready = true;
}
cv.notify_one();
}
}
void consumer()
{
while (true)
{
std::unique_lock<std::mutex> lock{ m };
cv.wait(lock, []{ return ready == true; });
std::cout << data << '\n';
ready = false;
}
}
int main()
{
std::thread tp{ producer };
std::thread tc{ consumer };
tp.join();
tc.join();
}
uj5u.com熱心網友回復:
while執行緒中回圈的每次迭代都producer需要一個鎖,計算data,設定ready=true,然后在重復之前解鎖。
在睡眠陳述句未被注釋掉的情況下:
由于互斥體在呼叫時仍由作業系統持有sleep,因此生產者和消費者執行緒都被有效地暫停,并且沒有被給予任何運行時間。
然后 sleep 陳述句完成。這使生產者執行緒能夠喚醒(具有完整的量程)。生產者執行緒在量子時間內可能正在嘗試執行以下操作:
- 放
ready=true - 由于范圍完成而解鎖互斥鎖
- 呼叫
notify_one以向消費者執行緒發出信號,它可以得到一個鏡頭。但請記住,當生產者執行緒正在運行時,消費者執行緒可能會在此時暫停。 - 重新獲取這些鎖。
同時消費者執行緒在wait呼叫中被阻塞。notify_one但是,當生產者執行緒呼叫該呼叫時,它最終會發出可以運行的信號。那么這可能會發生:
消費者執行緒將在上述生產者執行緒的第 3 步中被喚醒。執行緒的暫存器狀態和其他內容將由作業系統恢復。這需要幾個周期。然后它嘗試自己獲取鎖。但是當它試圖獲取鎖時,生產者執行緒已經再次抓住了它,因為它已經在運行并且沒有被任何東西阻塞。
現在,我在未注釋 sleep 陳述句的情況下運行了您的程式。它偶爾會列印一行count: XX,但很少。有一個小視窗,消費者執行緒可以在其中“贏得”與生產者執行緒的競爭并獲得互斥鎖。但這需要多次迭代和一些運氣。在我在本地構建和運行原始代碼sleep且未注釋陳述句的復制中,程式在運行幾分鐘后準確地列印了這一行,沒有其他任何內容。
count: 41
它恰好在 sleep 陳述句被注釋掉時起作用,因為執行緒調度程式只是偶爾在對互斥體的解鎖和鎖定呼叫之間的執行緒之間進行背景關系切換。根據系統上可用內核的數量,您甚至可能會有不同的行為。作為證據,您可以看到consumer執行緒在每次連續列印呼叫時都會跳過一堆值。這是因為生產者執行緒從來沒有像消費者執行緒在coutandwait陳述句中那樣在 i/o 上被阻塞。
count: 131
count: 134
count: 2661
count: 2804
count: 2880
...
我猜你想讓消費者執行緒列印分配給資料的每個新值。如果是這種情況,請在睡眠時解鎖互斥鎖。我們可以在 sleep 陳述句之間解鎖和重新鎖定互斥鎖。但只需交換一些行就足夠了:
void producer()
{
int c{};
while (true)
{
c;
{
std::unique_lock<std::mutex> lock{ m };
data = "count: " std::to_string(c);
ready = true;
}
cv.notify_one();
std::this_thread::sleep_for(std::chrono::seconds{ 1 });
}
}
這將導致consumer列印出每個唯一值data而不是跳過任何:
count: 1
count: 2
count: 3
count: 4
count: 5
count: 6
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/523271.html
標籤:C 多线程
