2016-12-15 107 views
2

我讀的C++ 11個線程的一些文獻,並試圖下面的代碼:混淆C++線程行爲

#include "iostream" 
#include "thread" 

using namespace std; 

class background_task{ 
    int data; 

    int flag; 

    public: 
     background_task(int val):data(val),flag(data%2){} 

     void operator()(void){ 
      int count = 0; 
      while(count < 100) 
      { 
       if(flag) 
        cout <<'\n'<<data++; 
       else 
        cout <<'\n'<<data--; 
       count++; 
      } 
     } 
}; 

int main(int argc , char** argv){ 
    std::thread T1 {background_task(2)}; 
    std::thread T2 {background_task(3)}; 
    T1.join(); 
    T2.join(); 
    return 0; 
} 

輸出無厘頭因爲我運行兩個線程所以每個應當印幾乎在一起,並沒有等待一個線程完成開始。相反,每個線程完成,然後下一個線程開始,就像同步的方式。我在這裏錯過了什麼?

+0

不,你不會錯過任何。這只是一個巧合。嘗試多次運行您的代碼並觀察。 – user3286661

回答

1

嘗試下面的代碼,修改前面的代碼顯示結果:

#include "iostream" 
#include "thread" 

using namespace std; 

class background_task{ 
    int data; 

    int flag; 

    public: 
     background_task(int val):data(val),flag(data%2){} 

     void operator()(void){ 
      int count = 0; 
      while(count < 10000000) 
      { 
       if(flag) 
        cout <<'\n'<<"Yes"; 
       else 
        cout <<'\n'<<" "<<"No"; 
       count++; 
      } 
     } 
}; 

int main(int argc , char** argv){ 
    std::thread T1 {background_task(2)}; 
    std::thread T2 {background_task(3)}; 
    T1.join(); 
    T2.join(); 
    return 0; 
} 

的時候第二個線程啓動第一線程已經處理完,因此你看到你看到了什麼。

+0

這很有道理,謝謝。 –

2

它可能是因爲創建一個新的線程需要一定的時間和下一個開始前的第一個線程完成。 ,你有選擇地分離或加入一個線程像

t1.detach();//don't care about t1 finishing 
or t1.join()//wait for t1 to finish 
2

您的操作系統不需要啓動的同時線程;它不需要在不同的內核上啓動它們;它不需要爲每個線程提供相等的時間。我真的不相信這個標準強制規定任何事情,但我沒有檢查標準來引用正確的部分來驗證。

您可以到(沒有承諾!)讓你改變你的代碼如下願望的行爲。這段代碼「鼓勵」操作系統爲兩個線程提供更多時間,並希望允許兩個線程在其中一個線程完成之前完全構建。

#include <chrono>             
#include <iostream>            
#include <thread>             

class background_task {           
public:               
    background_task(int val) : data(val), flag(data % 2) {}   
    void operator()() {            
    int count = 0;            
    while (count < 100) {           
     std::this_thread::sleep_for(std::chrono::milliseconds(50)); 
     if (flag)             
     std::cout << '\n' << data++;        
     else              
     std::cout << '\n' << data--;        
     count++;             
    }                
    }                
private:               
    int data;              
    int flag;              
};                

int main() {              
    std::thread T1{background_task(2)};        
    std::thread T2{background_task(3)};        
    T1.join();              
    T2.join();              
    return 0;              
}  
+0

如果您使用信號而不是睡眠,則可以在不浪費時間的情況下獲得相同的行爲。 – izlin

+0

@izlin這需要信號燈的理解 - 鑑於眼下的問題,我試圖讓少數的假設相對於以前的知識。 (玩這樣的事情就是我開始學習線程 - 把信號扔進混合可能不會促進我的理解,但希望這個答案有用。) – druckermanly

+0

你是對的。我只是想提一下,OP至少聽說過它。不應該是批評。 – izlin

1

除了阿米爾RASTI的答案,我認爲這是值得一提的調度。

如果使用while(1)相反,你會看到輸出是不完全甚至跑步「平行」兩個線程後平行。調度程序(操作系統的一部分)將爲每個進程運行時間,但時間可能會有所不同。因此,在調度程序讓另一個進程再次打印之前,一個進程可能會打印100個字符。

1
while(count < 10000) 

循環可能會在下一個線程開始之前完成,如果增加循環或在循環中插入一些睡眠,您可以看到差異。