2014-12-05 50 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