C++ 在c+中工作不正常的情况下在内部工作+;
我在C有一个奇怪的情况(至少对我来说是D)++ 我的代码是:C++ 在c+中工作不正常的情况下在内部工作+;,c++,multithreading,while-loop,C++,Multithreading,While Loop,我在C有一个奇怪的情况(至少对我来说是D)++ 我的代码是: static void startThread(Object* r){ while(true) { while(!r->commands->empty()) { doSomthing(); } } } 我使用boost作为线程启动这个函数,其中r中的命令是队列。。。我在另一个线程中填充此队列 问题是,如果我先填满队列,然后开始
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();
}
}
}
静态void startThread(Object*r){
while(true)
{
std::cout empty())
{
dosomshing();
}
}
}
我只是加了一句。。。它正在工作。。。有人能解释为什么它是与cout一起工作而不是与cout一起工作吗?或者有人知道会出什么问题
也许编译器正在进行某种优化?我不这么认为…:(
谢谢
但是如果我先运行startThread,然后再填充队列命令,它就不工作了…doSomething()将不会运行
当然不是!你期望什么?你的队列是空的,所以!r->commands->empty()
将是false
我刚刚加了cout…它正在工作
您很幸运。cout
相对较慢,因此您的主线程有机会在第一次执行内部测试之前填充队列
那么为什么在主线程填充了r->commands
之后,线程看不到更新版本的命令呢?因为代码中没有任何内容表明变量将从外部更改,所以编译器假定它不会更改
<>实际上,编译器看到你的代码> R< /C>的“强>不能< /强>更改,因此它可以从内部循环中删除冗余检查。当使用多线程代码时,你需要明确地告诉C++变量可以从不同的上下文中改变,使用.< /P>< P>当你先运行线程然后填充T时。不进入内部循环的队列是合乎逻辑的,因为test!r->commands->empty()
为true。在添加cout
语句后,它开始工作,因为打印输出需要一些时间,同时另一个线程填满了队列。因此该条件再次变为true。但在多线程环境中,依赖这一事实进行编程并不好。有两个相互关联的问题:
- 您没有强制重新加载
r->commands
或r->commands-Yempty()
,因此,您的编译器在努力寻找性能顶峰的同时,缓存了结果。如果无法证明缓存仍然有效,则添加更多代码可能会使编译器删除此优化
- 您有一个数据竞争,因此您的程序有未定义的行为。(我假设
doSomething()
删除一个元素,其他一些线程添加元素。
1.10多线程执行和数据争用§21
如果程序在不同线程中包含两个冲突的操作,则程序的执行包含数据竞争,
其中至少有一个不是原子的,而且两个都不是在另一个之前发生的
未定义的行为。[注意:可以显示正确使用互斥量和内存顺序的程序_-
seq_cst防止所有数据争用且不使用其他同步操作的操作的行为与
由其组成线程执行的操作被简单地交错,每个值的计算
对象从该交织中对该对象的最后一个副作用中提取。这通常称为
“顺序一致性”。然而,这仅适用于无数据竞争程序和无数据竞争程序
无法观察大多数不改变单线程程序语义的程序转换。在
事实上,大多数单线程程序转换仍然被允许,因为
因此,必须执行未定义的操作。-结束注释]
二十二
如果只发送空队列,线程将很快结束。当您进行打印时,父线程将有机会填充队列。请使用一些同步。如果队列不是线程安全的,则从2个线程更新队列可能会导致未定义的结果。它正在“工作”使用cout是因为您有一个bug,它导致的减速是掩蔽。首先,您需要使用某种同步机制来保护对队列的访问。@Dusan Plavak-,但是如果我先运行startThread
,这就是问题所在。您认为当您调用启动线程的函数时,线程函数立即执行。这是一个错误的假设。如果不使用(甚至不学习)编写多线程程序,您将无法逃脱惩罚关于正确的同步,例如信号量、互斥体、原子操作等@PaulMcKenzie我没有假设哪个线程先启动,我确保startThread先启动…不管怎样,问题就像Konrad Rudolph在提供链接时描述的那样…@DusanPlavak-您如何确保startThread函数先启动st?您的问题中不清楚该函数是如何启动的。您是否直接调用startThread函数?startThread();FillUpTheQueue();
您是这样做的?还是这样做的:callThreadedFunction(startThread);FillUpTheQueue()
?callThreadedFunction
是一些启动线程的通用函数(不管它是不是boost).我不认为是这样,因为对象r是指针,所以如果我以后感觉到命令是否为空,这并不重要…?外部而轮询r->commands
列表。但是编译器没有识别,对象是从“外部”更改的。您必须使用volatile命令告诉编译器。@KonradRudolph W