线程比std :: conditional_variable :: wait()更快地锁定互斥锁

时间:2017-05-09 00:19:14

标签: c++ multithreading c++11

我试图了解condition_variables。

我想我的代码应该像以下一样工作:
主锁mx
2. main wait()notify< =此处锁定释放
3.线程锁定mx
4.线程发送通知
5.线程解锁mx
6. main wait()完成并锁定mx

那么为什么线程可以在通知后比wait()调用更快地锁定mx? 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;
        }
    }
}

1 个答案:

答案 0 :(得分:2)

这取决于您的操作系统如何安排等待获取互斥锁的线程。所有execute个线程都在等待在第一个notify_one之前获取互斥锁,所以如果有一个简单的线程FIFO队列等待锁定互斥锁,那么它们都在main之前。 {1}}队列中的线程。当每个互斥锁解锁互斥锁时,队列中的下一个锁定它。

这与互斥锁没有任何关系更快&#34;条件变量必须锁定相同的互斥锁才能从等待返回。

一旦未来准备就绪,所有execute个线程都会从wait返回,并且所有线程都会尝试锁定互斥锁,加入服务器队列。当条件变量开始等待时,互斥锁被解锁,其他线程之一(队列前面的那个)获得锁定。它调用notify_one导致条件变量尝试重新锁定互斥锁,加入队列的后面。通知线程解锁互斥锁,并且队列中的下一个线程获得锁定,并调用notify_one(由于条件变量已经通知并等待锁定互斥锁,因此不执行任何操作)。然后队列中的下一个线程获取互斥锁,依此类推。

似乎其中一个execute线程在第一次notify_one调用之前没有足够快地进入队列,所以它最终进入条件变量后面的队列中。