2016-12-27 123 views
3

請參見下面的代碼:在這種簡單的情況下可能發生死鎖嗎?

std::mutex mutex; 
std::condition_variable cv; 
std::atomic<bool> terminate; 

// Worker thread routine 
void work() { 
    while(!terminate) { 
     { 
      std::unique_lock<std::mutex> lg{ mutex }; 
      cv.wait(lg); 

      // Do something 
     } 
     // Do something 
    } 
} 

// This function is called from the main thread 
void terminate_worker() { 
    terminate = true; 
    cv.notify_all(); 
    worker_thread.join(); 
} 

在以下情況下會發生?

  1. 工作線程正在等待信號。
  2. 主線程叫做terminate_worker();
    • 主線程將原子變量terminate設置爲true,然後通知工作線程。
    • 工作線程現在醒來,完成工作並從terminate加載。在這一步,改爲terminate所做的主線程還沒有看到,所以工作線程決定等待另一個信號。
  3. 現在發生死鎖...

我不知道這是以往任何時候都可能。據我瞭解,std::atomic只保證沒有競爭條件,但記憶順序是不同的事情。問題:

  1. 這可能嗎?
  2. 如果這是不可能的,如果terminate不是一個原子變量,但這只是bool?或者原子性與此無關?
  3. 如果這是可能的,我該怎麼辦?

謝謝。

+0

['的std :: memory_order'](http://en.cppreference.com/w/cpp/atomic/memory_order) – melak47

+0

@ melak47請提供更多細節。我知道這是關於'std :: memory_order'。但我不知道'std :: condition_variable'如何處理內存順序限制。 –

+0

相關:http://stackoverflow.com/questions/8819095/concurrency-atomic-and-volatile-in-c11-memory-model – Leon

回答

2

我不相信,你描述什麼是可能的,因爲據我所知cv.notify_all()(請糾正我,如果我錯了)與wait()同步,所以當工作線程醒來,就會看到變化terminate

但是:

死鎖可能發生以下方式:

  1. 工作線程(WT)確定terminate標誌仍然是假的。

  2. 主線程(MT)設置terminate標誌並調用cv.notify_all()

  3. 由於沒有人正在等待條件變量通知被「丟失/忽略」。
  4. MT呼叫join和塊。
  5. WT進入睡眠狀態(cv.wait())並且阻止。

解決方案:

雖然你沒有,而你打電話cv.notify持有的鎖,你

  • 必須持有鎖,而你是修改terminate(即使它是原子的)
  • 必須確保在您持有相同的鎖時檢查條件和實際調用wait

這就是爲什麼有一種形式wait在它將線程發送到睡眠之前執行此檢查。

校正的代碼(具有最小的變化)可能看起來像這樣:

// Worker thread routine 
void work() { 
    while(!terminate) { 
     { 
      std::unique_lock<std::mutex> lg{ mutex }; 
      if (!terminate) { 
       cv.wait(lg); 
      } 

      // Do something 
     } 
     // Do something 
    } 
} 

// This function is called from the main thread 
void terminate_worker() { 
    { 
     std::lock_guard<std::mutex> lg(mutex); 
     terminate = true; 
    } 
    cv.notify_all(); 
    worker_thread.join(); 
} 
+0

在任何情況下,OP應在等待終止變量的狀態後檢查。在提供的代碼中,我們不能區分爲什麼通知條件變量。它可以是terminete請求,也可以是與另一個線程的正常同步。 – paweldac

+0

@paweldac:是的,他可能應該(不知道業務邏輯很難說),但是這與關於是否會發生死鎖的問題有什麼關係? – MikeMB

+1

爲什麼downvote? – MikeMB

相關問題