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

The thread has exited with code 1: Join() and Detach()

本文关键字:Join Detach 退出 代码 线程      更新时间:2023-10-16

我开发了一个软件,需要下载多个图像并使用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 ////
}

您的代码具有未定义的行为。loadimage填充imgrunimg读取,而无需任何同步。 这个凸轮会导致各种问题,其中之一是您当前观察到的问题。 要解决此问题,您需要使用某种同步来确保在写入时不会读取。 最简单的方法是将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。 也就是说,您可以通过将线程存储在容器中来解决此问题,然后在程序退出之前调用所有线程上的 join 以确保在应用程序终止之前完成所有操作。 您也可以为此利用线程池。