2016-06-12 52 views
0

我有一个消费者和两个生产者。 当我同时产生两个生产者时,他们似乎互相锁定,因为我们看到的第一个值分别是223和889。unique_lock跨线程

有人能解释一下这里发生了什么吗?

#include<vector> 
#include<thread> 
#include<iostream> 
#include<mutex> 
#include<chrono> 
#include <condition_variable> 

using namespace std; 

vector<double>testvec; 
mutex mtx; 
condition_variable cv; 

class Base 
{ 
public: 
    Base() {}; 
    void dosomething(); 
    int i; 
}; 

void Base::dosomething() 
{ 
    while(1) 
    { 
     std::unique_lock<std::mutex> ulck(mtx); 
     testvec.push_back(i); 
     ulck.unlock(); 
     cv.notify_all(); 
     i++; 
     std::this_thread::sleep_for (std::chrono::milliseconds(i)); 
    } 
}; 

class Derived1 : public Base 
{ 
public: 
    Derived1() {i = 222;} 
}; 

class Derived2 : public Base 
{ 
public: 
    Derived2() {i = 888;} 
}; 

class Consumer 
{ 
public: 
    Consumer() {} 
    void dostuff(); 
}; 

void Consumer::dostuff() 
{ 
    while(1) 
    { 
     std::unique_lock<std::mutex> ulck(mtx); //locks shared data 
     cv.wait(ulck); 
     cout<<"last value: "<<testvec.back()<<endl; 
     ulck.unlock(); 
    } 
} 

int main(int argc, char ** argv) 
{ 
    Derived1 derived1; 
    Derived2 derived2; 
    Consumer c; 

    std::thread t1(&Derived1::dosomething, &derived1); 
    std::thread t2(&Derived2::dosomething, &derived2); 
    std::thread t3(&Consumer::dostuff, &c); 

    t1.join(); 
    t2.join(); 
    t3.join(); 
} 

output is: 
last value: 223 
last value: 224 
last value: 225 
last value: 889 
last value: 226 
last value: 227 
last value: 228 
last value: 229 
last value: 890 
last value: 230 

expected output: 
last value: 888 (or 222) 
last value: 222 (or 888) 
last value: 223 
... 
+0

什么错输出? – fghj

+0

所以每次创建新数据。消费者进行计算并将其打印出来进行筛选。这没有发生。它的锁只是被两个派生类抓住,但没有做任何事情。 – acv17

+0

@ user1034749,我在运行的实际代码中重新创建了相同的问题。希望这是有道理的。有任何想法吗? – acv17

回答

1

你永远不会从wait没有谓词得到理智的行为。另外,为什么你只是为了立即锁定而继续释放锁?

这是你ened做什么:

void Consumer::dostuff() 
{ 
    std::unique_lock<std::mutex> ulck(mtx); //locks shared data 
    int i = 0; 
    while(1) 
    { 

     // Correctly decide when to wait and when to stop waiting 
     while (testvec.empty() || (testvec.back() == i)) 
      cv.wait(ulck); 

     i = testvec.back(); 
     cout<<"last value: "<<testvec.back()<<endl; 
    } 
} 

条件变量是无状态的,也没有办法知道他们是否应该等待或当他们应该停止等待那些是共享状态的功能。您有责任编写该代码,使用互斥锁来保护共享状态。

注意此代码仅在需要等待时才调用wait。您只能通过检查共享状态来告诉您是否需要等待。并注意它在继续等待时继续呼叫wait。同样,您只能通过检查共享状态来判断是否可以停止等待。共享状态是你的责任 - 状态变量是无状态的。

0

我有一个消费者和两个生产者。

错误。你有2个生产者和一个采样者。没有消耗。

你可能想这是什么(简化后):

#include<deque> 
#include<thread> 
#include<iostream> 
#include<mutex> 
#include<chrono> 
#include <condition_variable> 

using namespace std; 

deque<double> testvec; 
mutex mtx; 
condition_variable cv; 

auto producer = [](int i) 
{ 
    while(1) 
    { 
     std::unique_lock<std::mutex> ulck(mtx); 
     testvec.push_back(i); 
     ulck.unlock(); 
     cv.notify_all(); 
     i++; 
     std::this_thread::sleep_for (std::chrono::milliseconds(i)); 
    } 
}; 

void consume() 
{ 
    while(1) 
    { 
     std::unique_lock<std::mutex> ulck(mtx); //locks shared data 


     // wait until there is something to consume... 
     cv.wait(ulck, [&]{return not testvec.empty(); }); 

     /// ... consume it... 
     auto val = testvec.front(); 
     testvec.pop_front(); 

     /// ... now unlock and work with the consumed data while unlocked 
     ulck.unlock(); 

     /// ... do work 
     cout<<"last value: " << val <<endl; 
    } 
} 

int main(int argc, char ** argv) 
{ 
    std::thread t1(producer, 222); 
    std::thread t2(producer, 888); 
    std::thread t3(consume); 

    t1.join(); 
    t2.join(); 
    t3.join(); 
} 

输出示例:

last value: 222 
last value: 888 
last value: 223 
last value: 224 
last value: 225 
last value: 889 
last value: 226 
...