2014-12-05 48 views
1

任何人都可以指出我做错了什么吗?
我希望foo和bar被交替打印。
有时它会在第一次迭代中挂起,并且在某些情况下会在停止之前持续一段时间。使用条件变量进行双向通信时发生死锁

#include <thread> 
#include <mutex> 
#include <condition_variable> 
std::mutex m; 
std::condition_variable cv; 
void foo() 
{ 
    while(true) 
    { 
     std::unique_lock<std::mutex> ul(m); 
     cv.wait(ul); 
     std::cout<<"bar"<<std::endl; 
     ul.unlock(); 
     cv.notify_one(); 
    } 
} 
int main() 
{ 
    std::thread t(foo); 
    while(true) 
    { 
     std::cout<<"foo"<<std::endl; 
     cv.notify_one(); 
     std::unique_lock<std::mutex> ul(m); 
     cv.wait(ul); 
    } 
} 
+0

你忘了实际的沟通!你有一个互斥体,但它不能保护任何东西! – 2014-12-05 07:58:33

回答

1

条件变量只发出变化信号,它们本身并不是很有用。你需要把它和一个状态结合起来。

添加另一个变量,它决定了它的转向。

std::mutex m; 
std::condition_variable cv; 
int turn = 0; 

void foo() 
{ 
    while(true) 
    { 
     std::unique_lock<std::mutex> ul(m); 
     if(turn == 1) { 
      // my turn 
      std::cout << "bar" << std::endl; 

      // tell them it's their turn 
      turn = 0; 
      cv.notify_one(); 
     } else { 
      // not our turn, wait for a change. 
      cv.wait(ul); 
     } 
    } 
} 

int main() 
{ 
    std::thread t(foo); 
    while(true) 
    { 
     std::unique_lock<std::mutex> ul(m); 
     if(turn == 0) { 
      // my turn 
      std::cout << "foo" << std::endl; 

      // tell them it's their turn 
      turn = 1; 
      cv.notify_one(); 
     } else { 
      // not our turn, wait for a change. 
      cv.wait(ul); 
     } 
    } 
} 

互斥用于安全访问turn变量,每当它改变,你将情况通知变量,以便其他线程可以唤醒并检查新的价值。


编辑:假设你理解了上面,解决您的难题:

void foo() 
{ 
    std::unique_lock<std::mutex> ul(m); 
    while(true) 
    { 
     std::cout << "bar" << std::endl; 
     cv.notify_one(); 
     cv.wait(ul); 
    } 
} 

int main() 
{ 
    std::unique_lock<std::mutex> ul(m); 
    std::thread t(foo); 
    while(true) 
    { 
     std::cout << "foo" << std::endl; 
     cv.notify_one(); 
     cv.wait(ul); 
    } 
} 

换句话说,你只需要在循环外锁互斥体,启动子线程之前,所以对于第一个轮到的逻辑来说很清楚。然后你做这个动作,发出信号,然后等待另一个线程发回信号。

流逻辑的:

Main Thread    Sub Thread 
------------------------------------------ 
Lock Mutex 

Create Subthread 

         Try to lock mutex 
         but it is busy. 

Print "foo"    ...waiting for mutex... 

Notify cvar    ignores notification, 
         (still waiting for mutex) 

Wait on cvar   Obtains lock 
         (when waiting on a cvar, the lock is released.) 

...waiting...   Prints "bar" 

Notified, but the  Notify cvar 
mutex is still locked   
so we are waiting. 

Obtains lock again  Wait on cvar 

Print "foo"    ...waiting... 

(etc...) 
+0

只需锁定主要的互斥锁,就像第二个示例一样正常工作。为什么我应该有额外的转弯标志? – manasij7479 2014-12-05 08:18:47

+0

它在实际场景中更有用,而第二个例子有效,它根本不灵活 – mukunda 2014-12-05 16:08:55

+0

除非另一个线程一直等待通知,否则它不起作用。换句话说,它不是多线程的。 – mukunda 2014-12-05 16:28:08

0

好吧。 main调用notify,然后foo调用notify,然后main锁定互斥锁并等待,然后foo阻止互斥锁。僵局。

+0

我如何实现这种沟通? – manasij7479 2014-12-05 06:02:58