在内部,而在c ++中不能正常工作

时间:2014-04-30 10:32:54

标签: c++ multithreading while-loop

我在C ++中有好奇的情况(至少对我而言:D)

我的代码是:

static void startThread(Object* r){
    while(true)
    {
        while(!r->commands->empty())
        {
            doSomthing();
        }
    }
}

我使用boost启动此函数,其中r中的命令是队列...这个队列我填入另一个线程......

问题在于,如果我先填充队列,然后开始这个步骤,一切正常......但是如果我先运行startThread,然后填充队列命令,那就不行了...... doSomething()不会跑...

如果我修改startThread怎么办:

static void startThread(Object* r){
    while(true)
    {
        std::cout << "c" << std::endl;
        while(!r->commands->empty())
        {
            doSomthing();
        }
    }
}

我刚添加cout ......它正在工作......任何人都可以解释为什么它与cout合作而不是没有?或者任何人都知道什么是错的?

也许编译器正在进行某种优化?我不这么认为... :( 感谢

3 个答案:

答案 0 :(得分:3)

  

但是,如果我先运行startThread,之后我会填充队列命令,它就无法运行... doSomething()将无法运行

当然不是!你有什么期望?您的队列为空,因此!r->commands->empty()将为false

  

我刚添加cout ......它正在运作

你很幸运。 cout相对较慢,因此您的主线程有机会在第一次执行内部while测试之前填充队列。

那么为什么线程在主线程填充之后没有看到r->commands的更新版本?因为代码中没有任何内容表明您的变量将从外部更改,因此编译器会假定它不会从外部更改。

事实上,编译器发现你的r的指针不能更改,因此它可以从内循环中删除冗余检查。使用多线程代码时,您明确需要告诉C ++可以使用atomic memory access从不同的上下文更改变量。

答案 1 :(得分:0)

当你第一次运行线程然后填满队列时,不进入内部循环是合乎逻辑的,因为test !r->commands->empty()为真。添加cout语句后,它正在工作,因为打印输出需要一些时间,同时另一个线程填满队列。所以情况再次成真。但是,在多线程环境中依赖这些事实并不是一个好的编程。

答案 2 :(得分:0)

有两个相互关联的问题:

  • 您没有强制重新加载r->commandsr->commands-Yempty(),因此您的编译器在努力寻找性能的顶峰时会缓存结果。如果无法证明缓存仍然有效,则添加更多代码可能会使编译器删除此优化。
  • 您有数据争用,因此您的程序具有未定义的行为。 (我假设doSomething()删除了一个元素,而其他一些线程添加了元素。

      

    1.10多线程执行和数据竞争§21

         

    如果程序的执行包含不同线程中的两个冲突操作,则执行程序包含数据争用,   其中至少有一个不是原子的,也不会发生在另一个之前。任何此类数据竞赛都会产生   未定义的行为。 [注意:可以显示正确使用互斥锁和memory_order_-的程序   seq_cst操作可以防止所有数据争用并且不使用其他同步操作   由它们的组成线程执行的操作被简单地交织,每个值计算一个   对象取自该交错中该对象的最后一个副作用。这通常被称为   “顺序一致性”。但是,这仅适用于无数据竞争的程序和无数据竞争的程序   无法观察大多数不改变单线程程序语义的程序转换。在   事实上,大多数单线程程序转换仍然是允许的,因为任何行为的程序   结果不同,必须执行未定义的操作。 - 尾注]   22

  •