螺纹在循环中冻结

Thread freezing in a while loop

本文关键字:冻结 循环      更新时间:2023-10-16

在GCC中进行编译以进行释放时,我会在算法中使用线程奇怪的行为。即使WILE条件发生变化,该线程也不会离开等待循环,好像只是死了。

我注意到的另一件事是,如果将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一起工作正常,就像看起来很奇怪

感谢您的关注。

在您的标志上有一个明显的竞赛条件:您在执行plot()的线程和执行decode()的线程中读取和写入lets_plot_data

您需要声明这些标志原子:

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

如果您还不熟悉这种问题,我建议您从Herb Sutter观看此视频。