c++ - 多线程程序仅适用于打印语句

标签 c++ multithreading c++11 race-condition

我希望我能想到一个更具描述性的标题,但事实就是这样。我有一些代码,我想用它来做一些图像处理。我还需要从那些处理过的图像中获取一些统计数据,我想在一个单独的线程上执行此操作,以便我的主线程可以继续进行图像处理。

除此之外,这是我的代码。它不应该真正相关,除了我的 Image 类包装了一个 OpenCV Mat(尽管据我所知我没有使用 OMP 或任何东西):

#include <thread>
#include <iostream>
#include <vector>
using namespace std;

//Data struct
struct CenterFindData{
    //Some images I'd like to store
    Image in, bpass, bpass_thresh, local_max, tmp;
    //Some Data (Particle Data = float[8])
    vector<ParticleData> data;
    //My thread flag
    bool goodToGo{ false };
    //Constructor
    CenterFindData(const Image& m);
};

vector<ParticleData> statistics(CenterFindData& CFD);
void operate(vector<CenterFindData> v_CFD);


..........................................
..........................................
..........................................


void operate(vector<CenterFindData> v_CFD){
    //Thread function, gathers statistics on processed images
    thread T( [&](){
        int nProcessed(0);
        for (auto& cfd : v_CFD){
            //Chill while the images are still being processed
            while (cfd.goodToGo == false){ 
                 //This works if I uncomment this print statement
                /*cout << "Waiting" << endl;*/ 
            }
            cout << "Statistics gathered from " << nProcessed++ << " images" << endl;
            //This returns vector<ParticleData>
            cfd.data = m_Statistics(cfd);
        }
    });

    //Run some filters on the images before statistics
    int nProcessed(0);
    for (auto& cfd : v_CFD){
        //Preprocess images
        RecenterImage(cfd.in);
        m_BandPass(cfd);
        m_LocalMax(cfd);
        RecenterImage(cfd.bpass_thresh);
        //Tell thread to do statistics, on to the next
        cfd.goodToGo = true;
        cout << "Ran filters on " << nProcessed++ << " images" << endl;
    }

    //Join thread
    T.join();
}

我认为 cout 的延迟是为了避免我遇到的某些竞争条件,但是什么?因为只有一个线程修改了 bool goodToGo,而另一个线程检查它,这应该是“门控”这两个函数的线程安全方式吗?

抱歉,如果有任何不清楚的地方,我对此很陌生,似乎犯了很多明显的 WRT 多线程编程错误。

谢谢你的帮助

  • 约翰

最佳答案

当你有:

 while (cfd.goodToGo == false){  }

编译器看不出有任何理由“重新加载”goodToGo 的值(它不知道这个值会受到其他线程的影响!)。所以它读取一次,然后永远循环。

打印某些东西有所不同的原因是,编译器不知道打印函数实际上会影响什么,不会影响什么,所以“以防万一”,它会重新加载该值(如果编译器可以“看到里面“所有的打印代码,它实际上可以决定 goodToGo 不会被打印改变,也不需要重新加载——但是有多少时间限制[或一些时间代理,比如作为“调用级别数”或“中间指令数”]编译器花在弄清楚这些事情上[当然可能会调用编译器实际上无法访问源代码的代码,例如对 write 或类似的系统调用。

然而,解决方案是使用线程安全机制来更新 goodToGo - 我们可以将 volatile 属性扔给变量,但这并不能保证例如,另一个处理器被“告知”该值已更新,因此可能会显着延迟更新值的检测[或什至在某些条件下无限]。

使用std::atomic_bool goodToGostoreload 函数来访问里面的值。这样,您就可以保证该值被正确地更新,并且“立即”(如在几十到数百个时钟周期之后)被另一个线程看到。

作为旁注,这可能应该是实际的答案:忙等待线程通常是一个坏主意,您可能应该查看一些线程原语来等待 condition_variable。或类似的。

关于c++ - 多线程程序仅适用于打印语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29330705/

相关文章:

c# - 当主 UI 线程卡住时,为什么我的 PC 为 'freeze'?

java - 为什么消费者线程无法从 Vector 中删除消息?

c++ - 为什么 list<unique_ptr> 中的 unique_ptr 的 std::move() 没有真正 move 它?

c++ - 关于windows iocp的一个问题

c++ - std::is_signed<bool>::value 是否保证返回 false?

c++ - Julia 表演建议

C++ 文件写入包括字符串的内存地址而不是内容

java - 使用超时和信号量进行线程阻塞

c++ - 文档{}的mongodb C++驱动程序编译错误

c++ - 什么时候允许对 c++11 中的类型进行 memcpyed?