简体   繁体   English

线程锁定互斥锁的速度比std :: conditional_variable :: wait()快

[英]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.

相关问题 std :: unique_lock的关系 <mutex> 和conditional_variable条件 - Relationship of std::unique_lock<mutex> and conditional_variable cond 使用std :: conditional_variable等待条件 - Using std::conditional_variable to wait on a condition C ++ std lib <mutex> , <conditional_variable> 库和共享内存 - C++ std lib <mutex>, <conditional_variable> libs and shared memory Windows上的std :: conditional_variable :: wait_for,std :: thread :: sleep_for受调整时钟的影响 - std::conditional_variable::wait_for, std::thread::sleep_for on Windows are affected by adjusting clock std :: conditional_variable :: notify_all不会唤醒所有线程 - std::conditional_variable::notify_all does not wake up all the threads 在主程序退出期间销毁等待std :: conditional_variable的线程的正确方法 - Proper way to destroy threads waiting on a std::conditional_variable during main program exit std::lock_guard 如何比 std::mutex::lock() 更快? - How can std::lock_guard be faster than std::mutex::lock()? 与conditional_variable一起使用时(unique)与unique_lock的开销 - (boost) overhead of a unique_lock when used with a conditional_variable 在互斥锁上使用多个 std::unique_lock,FIFO 中的所有线程等待进程? - Use multiple std::unique_lock on mutex, all threads in FIFO to wait process? 为什么 std::mutex 比 std::atomic 快? - Why is std::mutex faster than std::atomic?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM