2016-12-15 109 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) 

循环可能会在下一个线程开始之前完成,如果增加循环或在循环中插入一些睡眠,您可以看到差异。