成员变量在另一个线程中不会被更改?

时间:2014-01-09 18:36:53

标签: c++ multithreading c++11

几分钟前我问了一个问题,现在我遇到了一个新问题。 我有这样的代码:

class foo{
public:

    void loop(){
        this->running = true;

        while(this->running){
            // do stuff
        }
    }

    void exitLoop(){
        this->running = false;
    }

private:

    bool running;
};

int main(){
    foo theFoo = foo(); 

    thread fooLoop(&foo::loop, theFoo);

    // do stuff

    theFoo.exitLoop();

    fooLoop.join();
}

当我调用theFoo.exitLoop()时,running应设置为false,并且循环/线程应退出。但是当我调用exitLoop()时,while循环才会继续。当我在循环中检查running的值时,我得到true,但它应该是false,以便循环退出。

当我没有使用成员变量而是全局变量时,一切正常。 我究竟做错了什么?

2 个答案:

答案 0 :(得分:12)

您正在将theFoo的副本绑定到该主题;因此,在本地副本上调用exitLoop不会对该线程使用的副本产生任何影响。相反,你可以绑定一个指针:

thread fooLoop(&foo::loop, &theFoo);

或(包装)参考:

thread fooLoop(&foo::loop, std::ref(theFoo));

或使用lambda并通过引用捕获:

thread fooLoop([&]{theFoo.loop();});

你也可以通过使类不可复制来防止这样的错误:

class foo {
    foo(foo const &) = delete;             // delete the copy constructor
    void operator=(foo const &) = delete;  // delete the copy-assignment operator

    // ...
};

你也有竞争条件:如果在线程开始之前调用exitLoop,则线程会将running设置回true并永远运行。您应该在构造函数中设置标志。该标志也应该是原子的,或者由互斥锁保护,以同步更新。

答案 1 :(得分:0)

即使您修复了有关复制此对象的问题,也不能使用类似的bool进行同步。优化编译器可能会注意到this->running在该循环中不会被修改,并且可能得出结论,不需要反复检查其值。事实上,循环代码根本没有考虑其他线程的业务,它可能只是忽略它们。你必须使用atomic_bool。