该线程已退出,代码为1:Join()和Detach()

时间:2019-01-28 20:52:52

标签: c++ multithreading

我开发的软件需要下载一些图像并使用opencv进行一些处理。我正在使用curllib下载图像,所以基本上我是从不同的网络摄像机获取图像的。我想做的是同时下载这些图像,因此我尝试使用detach()并调用curllib。我尝试使用detach()的主要原因是不等待可能花费较长时间或超时的某些下载。所以我想处理主循环中可用的内容。当我使用detach()时,程序停止运行而没有出现任何错误或错误后,仅显示:

The thread .... has exited with code 1 

The thread ....has exited with code 1 

及之后:

The program.... has exited with code 1....

没有例外,没有错误,什么都没有。就是这样。

如果我更改为join(),它将永远不会停止。但是,有了加入,我需要等待所有线程下载所有图像或超时。

我将显示一个具有两个请购单的示例:

//create class
ProcessImage* camera1 = new ProcessImage;
ProcessImage* camera2 = new ProcessImage;

for (;;) {

  /* Must initialize libcurl before any threads are started */
  curl_global_init(CURL_GLOBAL_ALL);

  // Load Image into Class variable
  std::thread th(&ProcessImage::loadimage, camera1);
  if (th.joinable()) {
    th.detach();
  }

  std::thread th2(&ProcessImage::loadimage, camera2);
  if (th2.joinable()) {
    th2.detach();
  }

  // Process with Opencv
  camera1->run();
  camera2->run();

}

我的加载图片功能:

void ProcessImage::loadimage() {


    Mat loading;

    //insert user and password
    string password = ConfigData.username + ":" + ConfigData.password;

    // Loading image with Curl
    loading = curlImgClass(ConfigData.urlSnapshot.c_str(), password.c_str(), 5);


    lastfail = false;

    // Internal variable to store the downloaded image 
    img = loading.clone();


    if (loading.empty()) {

        lastfail = true;
        endoperation = true;

    }

    if (loading.total() < 500) {

        lastfail = true;
        endoperation = true;


    }
}

卷曲函数:

size_t  ProcessImage::write_dataClass(char *ptr, size_t size, size_t nmemb, void *userdata)
{
    vector<uchar> *stream = (vector<uchar>*)userdata;
    size_t count = size * nmemb;
    stream->insert(stream->end(), ptr, ptr + count);
    return count;
}

cv::Mat  ProcessImage::curlImgClass(const char *img_url, string userpass, int timeout)
{

    vector<uchar> stream;
    CURL *curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, img_url); //the img url
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); // pass the writefunction
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream); // pass the stream ptr to the writefunction
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5); // timeout if curl_easy hangs,
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);


    if (userpass != ":") {
        const char * c = userpass.c_str();
        curl_easy_setopt(curl, CURLOPT_USERPWD, c);
    }

    CURLcode res = curl_easy_perform(curl); // start curl
    curl_easy_cleanup(curl); // cleanup

    /* Check for errors */
    if (res != CURLE_OK) {

        //return imdecode(stream, -1); // 'keep-as-is'
        cv::Mat test(cv::Size(1, 1), CV_64FC1);
        return test; // 'keep-as-is'
    }
    else {
        return imdecode(stream, -1);
    }
}

如何使其与detach()一起使用? 我尝试了很多类似std::lock_guard<std::mutex>的控件,但没有任何效果,该软件不断退出。

编辑:两个功能中唯一使用的变量是img

int ProcessImage::run(){

        if ( (img.total() < 500)  || (lastfail == true)) {

            failcount = failcount + 1;

                // create a black window
                Mat imagefail(480, 640, CV_8UC3, Scalar(0, 0, 0));

               // putText(imagefail, "Connection Fail", cvPoint(480 / 2, 480 / 2), CV_FONT_HERSHEY_COMPLEX_SMALL, 1, CV_RGB(255, 255, 255), 1, 8, false);

                imshow(ConfigData.name.c_str(), imagefail);                
                waitKey(20);

                m_lock2 = false;

                std::cout << "connection fail \n";

                return -1; // load fail
            //}

        }
        else {

            failcount = 0;
        }



        Mat sendimage = img.clone();
        Mat opacity = sendimage.clone();

       //// do other stuff with sendimage now ////

}

1 个答案:

答案 0 :(得分:0)

您的代码具有未定义的行为。 loadimage填充img,而runimg读取而没有任何同步。该凸轮会导致各种问题,其中之一就是您当前正在观察的问题。要解决此问题,您需要使用某种同步方式,以确保在编写时不阅读。最简单的方法是将loadimagerun移动到单个线程中。这样,它们将针对每个对象连续运行,因此您没有机会进行数据争夺。这将使您的for循环看起来像

//create class
ProcessImage* camera1 = new ProcessImage;
ProcessImage* camera2 = new ProcessImage;

for (;;) {

  /* Must initialize libcurl before any threads are started */
  curl_global_init(CURL_GLOBAL_ALL);

  // Load Image into Class variable and process
  std::thread th([](){ camera1->loadimage(); camera1->run(); });
  std::thread th2([](){ camera2->loadimage(); camera2->run(); });


  // join or detach threads, if wanting to detach consider using a thread pool or adding threads to a container instead
  th.join(); // possibly detach
  th2.join(); // possibly detach

}

我在代码中使用了join,但是如果您不想等待,可能需要detach。也就是说,您可以通过以下方法解决该问题:将线程存储在容器中,然后在程序退出之前,对所有线程进行调用联接,以确保在应用程序终止之前一切都已完成。您也可以为此使用线程池。