2017-06-07 23 views
2

我写了一个非常简单的代码来重现我的问题。C++变量不会改变,直到线程完成

#include <iostream> 
#include "tools.h" //contains s_sleep() 
#include <thread> 
using namespace std; 

void change(int *i) 
{ 
     while (true) 
     { 
       *i = 4356; 
     } 
} 

int main() 
{ 
     int v=3; 
     cout << v <<endl; 
     thread t(change, &v); 
     s_sleep(1); //sleep one second 
     cout << v << endl; 
     t.join(); 
} 

输出为3,再次为3后。但是,当我改变一个行

//while (true) 

我收到3,一秒钟后4356.

怎么可能? 希望有人能帮助。

+10

请阅读有关数据竞赛的内容。你的程序因为它而产生未定义的行为。 – nwp

回答

2

请指定您正在使用的编译器。我使用的是Microsoft Visual C++编译器,在我的视觉工作室中,我看到两次都输出了3,然后是4356.

这是我在计算机上运行的代码。

#include <ctime> 
#include <thread> 
#include <iostream> 
using namespace std; 
void change(int *i) { 
    while (true) { // commented out this later, the result is same. 
     *i = 4356; 
    } 
} 

int main() { 
clock_t tstart = clock(); 
    int v = 3; 
    cout << v << endl; 
    thread t(change, &v); 
    while(double(clock() - tstart)/CLOCKS_PER_SEC < 3.0) { // Instead of your s_sleep 
     int x = 1; // Just a dummy instruction 
    } 
    cout << v << endl; 
    t.join(); 
    return 0; 
} 

对我的结果的解释是线程“t”不知道变量“v”的任何内容。它只是得到一个int类型的指针,它将指针位置的值直接编辑到内存中。因此,当主(第一个)线程 再次访问变量“v”时,它只读取分配给“v”的内存并打印它获取的内容。

而且,“tools.h”中的代码是什么?它与变量“v”有什么关系。

如果没有,那么它必须是编译器方差(您的编译器可能与我的不同,也许gcc或g ++?)。这意味着,您的编译器必须缓存(或类似的东西)变量才能更快地访问。就像在当前线程中一样,变量没有被改变,只要它被访问,编译器就会给出变量的旧值(编译器认为这个值不变)。 (我对此不太确定)

+0

正如问题的评论中所说:程序具有未定义的行为,所以如果它适用于您的编译器没有多大意义,那么在编译不同的配置时甚至可能会有所不同。存在CPU拥塞和缓存以及其他涉及从不同线程访问数据时可能导致不同结果的事情。总是使用'std :: atomic'或者用'std :: mutex'保护这个;他们可能会比较慢,但他们保证写在一个线程中的内容会反映在另一个线程中。 – stefaanv

+0

您是对的。最简单的解释是,程序具有未定义的行为,因为有时第二个线程中的代码比第一个线程早运行,有时反之亦然。 (因为两者相互平行) –

+0

你说得对。我使用的是GNU编译器套件,问题在于优化。我禁用了它,现在它工作了!谢谢! – JuliB

-1

这也可能是由于缓存。您首先读取一个线程的变量,然后从另一个线程处理该变量并从第一个线程再次读取该变量。编译器无法知道它在此期间发生了变化。 要安全地做到这一点,“v”必须被宣布为易失性

+3

如果你可以使用C++ 11,应该使用线程通信'std :: atomic',而不是'volatile' – stefaanv

+0

...我认为volatile会很好地解释这里发生的事情。作者只问“这怎么可能” – Tobi

+0

我们在2017年中,所以除了一些深度嵌入式系统外,C++ 11应该被视为C++。 “为了安全地做到这一点'v'必须被声明为volatile'意味着你建议使用volatile。易失性问题在于它有时可行,但在多核系统上可能会失败。这是一个编译器功能,但CPU /缓存对此一无所知,另请参阅https://stackoverflow.com/a/2485177/104774。唉,接受的答案(其他编译器/不优化)更糟糕。 – stefaanv