[英]Relationship of std::unique_lock<mutex> and conditional_variable cond
[英]Threads lock mutex faster than std::conditional_variable::wait()
我正在嘗試了解condition_variables。
我猜我的代碼應該像這樣工作:
1.主鎖
2. main wait()notify <= here鎖已釋放
3.線程鎖定mx
4.線程發送通知
5.線程解鎖MX
6. main wait()完成並鎖定mx
那么,為什么通知后線程鎖定mx的速度比wait()調用的速度快?
例
#include <iostream>
#include <future>
#include <condition_variable>
#include <vector>
using namespace std::chrono_literals;
std::shared_future<void> ready;
std::mutex finish_mx;
std::condition_variable finish_cv;
int execute(int val, const std::shared_future<void> &ready){
ready.wait();
std::lock_guard<std::mutex> lock(finish_mx);
std::cout<<"Locked: "<<val<<std::endl;
finish_cv.notify_one();
return val;
}
int main()
{
std::promise<void> promise;
auto shared = promise.get_future().share();
std::vector<std::future<int>> pool;
for (int i=0; i<10; ++i){
auto fut = std::async(std::launch::async, execute, i, std::cref(shared));
pool.push_back(std::move(fut));
}
std::this_thread::sleep_for(100ms);
std::unique_lock<std::mutex> finish_lock(finish_mx);
promise.set_value();
for (int i=0; pool.size() > 0; ++i)
{
finish_cv.wait(finish_lock);
std::cout<<"Notifies: "<<i<<std::endl;
for (auto it = pool.begin(); it != pool.end(); ++it) {
auto state = it->wait_for(0ms);
if (state == std::future_status::ready) {
pool.erase(it);
break;
}
}
}
}
示例輸出:
Locked: 6
Locked: 7
Locked: 8
Locked: 9
Locked: 5
Locked: 4
Locked: 3
Locked: 2
Locked: 1
Notifies: 0
Locked: 0
Notifies: 1
編輯
for (int i=0; pool.size() > 0; ++i)
{
finish_cv.wait(finish_lock);
std::cout<<"Notifies: "<<i<<std::endl;
auto it = pool.begin();
while (it != pool.end()) {
auto state = it->wait_for(0ms);
if (state == std::future_status::ready) {
/* process result */
it = pool.erase(it);
} else {
++it;
}
}
}
這取決於您的操作系統如何調度正在等待獲取互斥鎖的線程。 所有execute
線程已經在第一個notify_one
之前等待獲取互斥鎖,因此,如果有一個簡單的FIFO隊列在等待鎖定互斥鎖,則它們都在隊列中的main
線程之前。 當每個互斥鎖都解鎖互斥鎖時,隊列中的下一個互斥鎖會對其進行鎖定。
這與互斥鎖比條件變量“更快”無關,條件變量必須鎖定相同的互斥鎖以從等待中返回。
一旦將來准備就緒,所有execute
線程都將從wait
返回,並且所有人都嘗試鎖定互斥鎖,從而加入等待者隊列。 當條件變量開始等待時,互斥鎖將被解鎖,其他線程之一(位於隊列前面的線程)將獲得鎖。 它調用notify_one
,這使條件變量嘗試重新鎖定互斥鎖,從而加入了隊列的后面。 通知線程將互斥鎖解鎖,隊列中的下一個線程將獲得鎖,並調用notify_one
(這不會執行任何操作,因為條件變量已被通知並等待鎖定互斥鎖)。 然后,隊列中的下一個線程獲取互斥對象,依此類推。
似乎其中一個execute
線程運行得不夠快,無法在第一個notify_one
調用之前進入隊列,因此它最終出現在條件變量后面的隊列中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.