线程锁定互斥快于std :: conditional_variable :: wait()
问题描述:
我想了解condition_variables。线程锁定互斥快于std :: conditional_variable :: wait()
我想我的代码应该像:
1.主锁MX
2.主要的wait()通知< =这里锁定解除
3.螺纹锁MX
4线程发送通知
5线程解锁mx
6.主等待()完成并锁定mx
那么为什么线程可以在通知后锁定mx比wait()更快?
Example
#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
之前等待获取互斥锁,因此如果有一个简单的先进先出线程队列等待锁定互斥锁,那么它们都会排在队列中的main
线程之前。当每个互斥锁解锁互斥锁时,队列中的下一个锁定它。
这与互斥锁比条件变量“更快”无关,条件变量必须锁定相同的互斥锁才能从等待中返回。
只要未来准备就绪,所有execute
线程将从wait
返回,并且所有尝试锁定该互斥锁并加入等待者队列。当条件变量开始等待时,互斥锁被解锁,并且其他线程之一(队列前面的线程)获得锁定。它调用notify_one
,这会导致条件变量尝试重新锁定互斥锁,并加入队列的后面。通知线程解锁互斥锁,并且队列中的下一个线程获取锁,并调用notify_one
(它不会执行任何操作,因为条件变量已经通知并且正在等待锁定互斥锁)。然后,队列中的下一个线程将获取互斥锁,依此类推。
看起来execute
线程中的一个在第一次调用notify_one
之前没有足够快地进入队列,所以它最终位于条件变量后面的队列中。
那么在notify_one()之后获得结果的最好方法是检查所有未来吗? – Alex
我不明白你在问什么,对不起。如果你想在'notify_one'调用和条件变量唤醒之间建立一对一的对应关系,那么你需要使用多个条件变量或者不同形式的同步。 –