2017-04-10 226 views
1

似乎是thread1功能並沒有得到執行C++線程不執行

#include <iostream> 
    #include <fstream> 
    #include <thread> 
    #include <condition_variable> 
    #include <queue> 

    std::condition_variable cv; 
    std::mutex mu; 
    std::queue<int> queue; 
    bool ready; 

    static void thread1() { 
     while(!ready) {std::this_thread::sleep_for(std::chrono::milliseconds(10));} 

     while(ready && queue.size() <= 4) { 
       std::unique_lock<std::mutex> lk(mu); 
       cv.wait(lk, [&]{return !queue.empty();}); 

       queue.push(2); 
     } 
    } 

    int main() { 
     ready = false; 
     std::thread t(thread1); 

     while(queue.size() <= 4) { 
      { 
       std::lock_guard<std::mutex> lk(mu); 
       queue.push(1); 
      } 

      ready = true; 
      cv.notify_one(); 
     } 

     t.join(); 

     for(int i = 0; i <= queue.size(); i++) { 
       int a = queue.front(); 
       std::cout << a << std::endl; 
       queue.pop(); 
     } 

     return 0; 
} 

我的Mac上的輸出是1 2 1 2但在我的Ubuntu其1 1 1。我正在編譯g++ -std=c++11 -pthread -o thread.out thread.cpp && ./thread.out。我錯過了什麼嗎?

+0

不能保證在主循環再次鎖定之前,thread1將能夠獲取互斥鎖。這就是多線程的方式,它可能是不可預測的。 –

+0

但我認爲thread1中的條件變量會用等待鎖定互斥鎖,並同時將main和thread1同步。我能做些什麼來同步順序運行? – Seph

+0

你有一個競爭條件。 ''thread''可以在'main'執行'queue.push(1)'時執行'queue.size()',並且行爲是不確定的。 – GManNickG

回答

0

我能夠通過使第二個線程在單獨的條件變量上的單獨謂詞上等待來解決這個問題。我不確定queue.size()是否是線程安全的。

#include <iostream> 
#include <fstream> 
#include <thread> 
#include <condition_variable> 
#include <queue> 

std::condition_variable cv; 
std::condition_variable cv2; 
std::mutex mu; 
std::queue<int> queue; 
bool tick; 
bool tock; 

static void thread1() { 
while(queue.size() < 6) { 
    std::unique_lock<std::mutex> lk(mu); 
    cv2.wait(lk, []{return tock;}); 

    queue.push(1); 

    tock = false; 
    tick = true; 
    cv.notify_one(); 
} 
} 

int main() { 
tick = false; 
tock = true; 
std::thread t(thread1); 

while(queue.size() < 6) { 
    std::unique_lock<std::mutex> lk(mu); 
    cv.wait(lk, []{return tick;}); 

    queue.push(2); 

    tick = false; 
    tock = true; 
    cv2.notify_one(); 
} 

t.join(); 

while(!queue.empty()) { 
    int r = queue.front(); 
    queue.pop(); 

    std::cout << r << std::endl; 
} 

return 0; 
} 
2

此:

for(int i = 0; i <= queue.size(); i++) { 
    int a = queue.front(); 
    std::cout << a << std::endl; 
    queue.pop(); 
} 

是不確定的行爲。 for循環從0到size運行size+1次。我建議你寫的更地道風格的隊列:

while(!queue.empty()) { 
    int a = queue.front(); 
    std::cout << a << std::endl; 
    queue.pop(); 
} 

當我coliru運行此,我以爲運行某種* nix的機器,我得到4 1的:http://coliru.stacked-crooked.com/a/8de5b01e87e8549e

此外,您還沒有指定任何會強制每個線程運行一定次數的任何內容。無論哪種方式,只有(嘗試*)會導致隊列大小達到4的不變量。恰巧在我們運行它的機器上,線程2從來沒有設法獲取互斥鎖。

如果您在各個點添加更多作業甚至(僅出於教學目的)延遲,此示例將更有趣。模擬兩個線程實際上正在工作。如果你在各個點上添加睡眠,你可以確保這兩個線程交替,儘管取決於你添加它們的位置,你可能會看到線程中斷的4個元素的不變量!

*請注意,即使您的4個元素不變的隊列,並不真正是一個不變量。當隊列中有3個元素時,線程可能(雖然不太可能)在同一時刻同時傳遞while條件。首先獲得鎖,然後推動另一個。所以你可以在隊列中包含5個元素! (如你所見,異步編程很棘手)。特別是當你有鎖的時候,你真的需要檢查隊列的大小,以便它能夠工作。