线程冻结在一个while循环中

时间:2017-09-30 19:51:09

标签: c++ multithreading

在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一样好用,看起来很奇怪

感谢您的关注。

1 个答案:

答案 0 :(得分:2)

你的旗帜上有一个明显的竞争条件:你在执行lets_plot_data的线程和执行plot()的线程中读写decode()并且没有任何事情阻止这种情况发生同时。

你需要将这些标志声明为原子:

    atomic<bool> some_data_ready { false };
    atomic<bool> lets_plot_data { false };

如果您还不熟悉此类问题,建议您观看this video from Herb Sutter