[英]Threads lock mutex faster than std::conditional_variable::wait()
I'm trying to understand condition_variables. 我正在尝试了解condition_variables。
I guess my code should work like: 我猜我的代码应该像这样工作:
1. main lock mx 1.主锁
2. main wait() notify <= here lock released 2. main wait()notify <= here锁已释放
3. threads lock mx 3.线程锁定mx
4. threads send notify 4.线程发送通知
5. threads unlock mx 5.线程解锁MX
6. main wait() finished and lock mx 6. main wait()完成并锁定mx
So why threads can lock mx faster than wait() call after notify? 那么,为什么通知后线程锁定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;
}
}
}
}
example output: 示例输出:
Locked: 6
Locked: 7
Locked: 8
Locked: 9
Locked: 5
Locked: 4
Locked: 3
Locked: 2
Locked: 1
Notifies: 0
Locked: 0
Notifies: 1
Edit 编辑
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;
}
}
}
This depends on how your OS schedules threads that are waiting to acquire a mutex lock. 这取决于您的操作系统如何调度正在等待获取互斥锁的线程。 All the
execute
threads are already waiting to acquire the mutex lock before the first notify_one
, so if there's a simple FIFO queue of threads waiting to lock the mutex then they are all ahead of the main
thread in the queue. 所有
execute
线程已经在第一个notify_one
之前等待获取互斥锁,因此,如果有一个简单的FIFO队列在等待锁定互斥锁,则它们都在队列中的main
线程之前。 As each mutex unlocks the mutex, the next one in the queue locks it. 当每个互斥锁都解锁互斥锁时,队列中的下一个互斥锁会对其进行锁定。
This has nothing to do with mutexes being "faster" than condition variables, the condition variable has to lock the same mutex to return from the wait. 这与互斥锁比条件变量“更快”无关,条件变量必须锁定相同的互斥锁以从等待中返回。
As soon as the future becomes ready all the execute
threads return from the wait
and all try to lock the mutex, joining the queue of waiters. 一旦将来准备就绪,所有
execute
线程都将从wait
返回,并且所有人都尝试锁定互斥锁,从而加入等待者队列。 When the condition variable starts to wait the mutex is unlocked, and one of the other threads (the one at the front of the queue) gets the lock. 当条件变量开始等待时,互斥锁将被解锁,其他线程之一(位于队列前面的线程)将获得锁。 It calls
notify_one
which causes the condition variable to try to relock the mutex, joining the back of the queue. 它调用
notify_one
,这使条件变量尝试重新锁定互斥锁,从而加入了队列的后面。 The notifying thread unlocks the mutex, and the next thread in the queue gets the lock, and calls notify_one
(which does nothing because the condition variable is already notified and waiting to lock the mutex). 通知线程将互斥锁解锁,队列中的下一个线程将获得锁,并调用
notify_one
(这不会执行任何操作,因为条件变量已被通知并等待锁定互斥锁)。 Then the next thread in the queue gets the mutex, and so on. 然后,队列中的下一个线程获取互斥对象,依此类推。
It seems that one of the execute
threads didn't run quickly enough to get in the queue before the first notify_one
call, so it ended up in the queue behind the condition variable. 似乎其中一个
execute
线程运行得不够快,无法在第一个notify_one
调用之前进入队列,因此它最终出现在条件变量后面的队列中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.