2017-05-09 28 views
0

我想了解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; 
     } 
    } 
} 

回答

2

这取决于您的操作系统调度线程正在等待如何获取互斥锁。所有execute线程已经在第一个notify_one之前等待获取互斥锁,因此如果有一个简单的先进先出线程队列等待锁定互斥锁,那么它们都会排在队列中的main线程之前。当每个互斥锁解锁互斥锁时,队列中的下一个锁定它。

这与互斥锁比条件变量“更快”无关,条件变量必须锁定相同的互斥锁才能从等待中返回。

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

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

+0

那么在notify_one()之后获得结果的最好方法是检查所有未来吗? – Alex

+0

我不明白你在问什么,对不起。如果你想在'notify_one'调用和条件变量唤醒之间建立一对一的对应关系,那么你需要使用多个条件变量或者不同形式的同步。 –