我正在开发一个基于客户端请求的服务器应用程序,它使用OpenCV库执行某些图像处理操作。应用程序的性质要求使用多个线程。最近,我一直在处理一个非常顽固的错误,该错误会导致段错误。我能够将发生分段错误的代码部分归零。
这是最小的实现。
#include <iostream>
#include <thread>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
int main() {
cv::Mat img_input = cv::Mat::zeros(cv::Size(240, 320), CV_8UC1);
cv::Mat img_output = cv::Mat::zeros(cv::Size(240, 320), CV_8UC1);
int i = 1;
while (i < 100) {
std::cout << "- - - - - - - - - - - - - - " << i++ << std::endl;
std::thread([&]() {
std::cout << "Thread started." << std::endl;
cv::Canny(img_input, img_output, 10, 20);
std::cout << "Thread finished." << std::endl;
}).join();
std::cout << "Thread joined." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(150));
}
return 0;
}
该程序失败,并显示2个不同的输出。有了这个输出...
- - - - - - - - - - - - - - 1
Thread started.
Thread finished.
Thread joined.
- - - - - - - - - - - - - - 2
Thread started.
Segmentation fault (core dumped)
..或与此。
- - - - - - - - - - - - - - 1
Thread started.
Thread finished.
Thread joined.
- - - - - - - - - - - - - - 2
Thread started.
Thread finished.
Segmentation fault (core dumped)
让我分享我的其他发现。 segfault仅在我安装了OpenCV版本3.3.0-dev的嵌入式linux设备(Toradex Colibri iMX6-模块计算机)上发生。仅当我在新线程中使用Canny()函数时,才导致段错误。我试过也调用其他OpenCV函数,但没有一个会产生任何错误。
当我在PC(Ubuntu 16.04,OpenCV版本3.3.0)上运行该程序时,不会发生段错误。
有什么想法吗?
****** 更新1 ******
我试图遵循评论中的一些建议。但是问题仍然存在。
我将Mat变量移动到每个线程的作用域内,以使它们在线程本地。我还增加了一些额外的睡眠时间来等待线程完成。
这是我的新实现。
#include <iostream>
#include <thread>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
void run() {
cv::Mat img_input = cv::Mat::zeros(cv::Size(240, 320), CV_8UC1);
cv::Mat img_output = cv::Mat::zeros(cv::Size(240, 320), CV_8UC1);
std::cout << "Thread started." << std::endl;
cv::Canny(img_input, img_output, 10, 20);
std::cout << "Thread finished." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
int main() {
int i = 1;
while (i < 100) {
std::cout << "- - - - - - - - - - - - - - " << i++ << std::endl;
std::thread t1(run);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "Waiting to join thread." << std::endl;
t1.join();
std::cout << "Thread joined." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
return 0;
}
输出再次在...之间变化
- - - - - - - - - - - - - - 1
Thread started.
Thread finished.
Waiting to join thread.
Thread joined.
- - - - - - - - - - - - - - 2
Thread started.
Thread finished.
Segmentation fault (core dumped)
...和...
- - - - - - - - - - - - - - 1
Thread started.
Thread finished.
Waiting to join thread.
Thread joined.
- - - - - - - - - - - - - - 2
Thread started.
Segmentation fault (core dumped)
****** 更新2 ******
我发现了一个帖子,其问题类似here。建议将以下行添加到代码中可以解决此问题。
cv::setNumThreads(0);
我已经在我的 main()函数的开头添加了这一行,似乎它解决了分段错误的问题。这是否有助于解释程序正在发生什么?
目前,这似乎是一个很好的快速解决方案,但是在我将其作为适当的解决方案接受之前,我想了解其背景。谁能解释为什么不再发生段错误?
有更好的解决方案吗?
答案 0 :(得分:1)
事实证明,将线程数设置为0或1可解决此问题(不再发生段错误)。这是通过以下两行代码之一完成的。
cv::setNumThreads(0); // Setting the number of thread to 0.
cv::setNumThreads(1); // Setting the number of thread to 1.
我不太了解OpenCV库,无法理解为什么会出现段错误以及为什么此行可以解决问题,但是目前我对结果感到满意,并将此问题标记为已回答。希望这对其他人有帮助。
答案 1 :(得分:0)
这只是一个评论,但我缺少相应的权利。抱歉。
该错误很可能不是由调用OpenCV引起的,而是由使用中的线程工具引起的。一种可能性是您在while循环中使用临时的std :: thread对象。尝试给它起一个名字,例如
std::thread worker([]...);
worker.join()
由于上述更改无济于事,因此该问题可能还处于较低级别(例如,图书馆冲突)。