我在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合作而不是没有?或者任何人都知道什么是错的?
也许编译器正在进行某种优化?我不这么认为... :( 感谢
答案 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->commands
或r->commands-Yempty()
,因此您的编译器在努力寻找性能的顶峰时会缓存结果。如果无法证明缓存仍然有效,则添加更多代码可能会使编译器删除此优化。doSomething()
删除了一个元素,而其他一些线程添加了元素。
1.10多线程执行和数据竞争§21
如果程序的执行包含不同线程中的两个冲突操作,则执行程序包含数据争用, 其中至少有一个不是原子的,也不会发生在另一个之前。任何此类数据竞赛都会产生 未定义的行为。 [注意:可以显示正确使用互斥锁和memory_order_-的程序 seq_cst操作可以防止所有数据争用并且不使用其他同步操作 由它们的组成线程执行的操作被简单地交织,每个值计算一个 对象取自该交错中该对象的最后一个副作用。这通常被称为 “顺序一致性”。但是,这仅适用于无数据竞争的程序和无数据竞争的程序 无法观察大多数不改变单线程程序语义的程序转换。在 事实上,大多数单线程程序转换仍然是允许的,因为任何行为的程序 结果不同,必须执行未定义的操作。 - 尾注] 22