在GCC中进行编译以进行发布时,我的算法中的线程会出现奇怪的行为。即使while条件发生变化,线程也不会离开等待循环,就像刚刚死掉一样。
我注意到的另一件事是,如果在等待循环中插入std::this_thread.sleep_for(10ms)
它可以正常工作,或者如果我编译为调试它也可以正常工作。
以下(伪)代码是代码的非常简化版本。
bool some_data_ready = false;
bool lets_plot_data = false;
bytearray packets; // a dynamic bytearray that holds a stream of packets
void decode(){
while(1){
if(packets.size() > 200){ // packets has data to be decoded
while (lets_plot_data) { //waiting loop
/* on the second run it gets stuck here becuse thread 1 dont
* leave its locking loop even if lets_plot_data changes
*/
//this_thread.sleep_for(10ms);
}
for(int i = 0;i< packets.size();++i){
if(packets.at(i) == 255){
if(packets.at(i+15) == 200){
//checks if packet has a start and an end
if(packets.at(14) == xor_checksum(packets.at(i))){
//packet is valid if calculated checksum is equal to the packet checksum
some_data_ready = true;
plot_data.push(packets.mid(i,15)); // copy a section starting at i len 15
// gets a packet and push it do be plotted
}
}
}
}
if(some_data_ready){
lets_plot_data = true;
some_data_ready = false;
}
}
}
}
void plot(){
while(1){
while (!lets_plot_data) { //thread dont leave here even if lets_plot_data changes
//this_thread.sleep_for(10ms);
}
graph.plot(plot_data); // not relevant, plots data at a graph
lets_plot_data = false;
}
}
std::thread* thread0;
std::thread* thread1;
std::thread* thread2;
int main(void){
thread0 = new std::thread(data); // gets data to be decoded (stream of ubytes containing packets)
thread1 = new std::thread(plot); // plot decoded data
thread2 = new std::thread(decode); // decodes data to be ploted
while(1){
//"gui loop"
}
return 0;
}
如果想知道,我的GCC发布标志是
-Ofast -msse -fomit-frame-pointer -fmodulo-sched -fmodulo-sched-allow-regmoves -fgcse-sm -fgcse-las -fgcse-after-reload -funsafe-loop-optimizations -flive-range-shrinkage -fsched-spec-load-dangerous -fsched2-use-superblocks -floop-nest-optimize -floop-parallelize-all -ftree-parallelize-loops=8 -fprefetch-loop-arrays -ffinite-math-only -march=native -mtune=native -mfpmath="387+sse" -std=c++17 -lstdc++ -static
但它也不适用于-O2
并且与-g -Og
一样好用,看起来很奇怪
感谢您的关注。
答案 0 :(得分:2)
你的旗帜上有一个明显的竞争条件:你在执行lets_plot_data
的线程和执行plot()
的线程中读写decode()
并且没有任何事情阻止这种情况发生同时。
你需要将这些标志声明为原子:
atomic<bool> some_data_ready { false };
atomic<bool> lets_plot_data { false };
如果您还不熟悉此类问题,建议您观看this video from Herb Sutter。