cv::remap segfaults with std::thread

匿名 (未验证) 提交于 2019-12-03 01:18:02

问题:

I am getting segfault with the following simple code:

#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp"  #include <iostream> #include <thread> #include <unistd.h>  void run() {     sleep(1);  // see below     cv::Mat source(10, 10, CV_32FC1, -1);      cv::Mat result(10, 10, CV_32FC1);     cv::Mat trX(result.rows, result.cols, CV_32FC1, 5);     cv::Mat trY(result.rows, result.cols, CV_32FC1, 5);      cv::remap(source, result, trX, trY, cv::INTER_LINEAR, cv::BORDER_TRANSPARENT);     std::cout << "done" << std::endl; }  int main(int argc, char* argv[]) {     std::thread t1(run);     t1.join();     std::thread t2(run);     t2.join();     return 0; } 

If I call run() twice directly from main(), without using threads at all, it works well. If I swap t1.join(); and std::thread t2(run); (that is, start the second thread before the first finishes; this is where sleep becomes important), it also runs well.

Moreover, if I change main to

int main(int argc, char* argv[]) {     std::thread t1(run);     std::thread t2(run);     t1.join();     t2.join();     std::thread t3(run);     t3.join();     return 0; } 

it segfaults in the third thread, but (strangely) not always: roughly one run of 2-3 passes successfully. However, I was not able to get a successfull run for the program with two threads above.

It seems that particular values in source, trX and trY are not important.

The big program that I was working on was running properly in December, after which I did not have time to work on it, but have updated the system several times. Now the big program fails with exactly the same segfault, so I think it should be something with newer versions of opencv and/or g++ and/or libstdc++.

Is it some problem with my system or my code? Or is it some known problem? Or where should I better report it?


I'm running up-to-date Ubuntu 16.10, with g++ 6.2.0 (I've also tried 4.9 with the same result). The specific versions of packages that may be of interest are:

$ dpkg-query -W -f='${binary:Package}\t${Version}\n' | grep -E '(g\+\+|c\+\+|opencv)' g++     4:6.1.1-1ubuntu2 g++-4.9 4.9.4-2ubuntu1 g++-5   5.4.1-2ubuntu2 g++-6   6.2.0-5ubuntu12 lib32stdc++6    6.2.0-5ubuntu12 libflac++6v5:amd64      1.3.1-4 libopencv-calib3d2.4v5:amd64    2.4.9.1+dfsg-2.1 libopencv-contrib2.4v5:amd64    2.4.9.1+dfsg-2.1 libopencv-core-dev:amd64        2.4.9.1+dfsg-2.1 libopencv-core2.4v5:amd64       2.4.9.1+dfsg-2.1 libopencv-features2d2.4v5:amd64 2.4.9.1+dfsg-2.1 libopencv-flann2.4v5:amd64      2.4.9.1+dfsg-2.1 libopencv-highgui-dev:amd64     2.4.9.1+dfsg-2.1 libopencv-highgui2.4-deb0:amd64 2.4.9.1+dfsg-2.1 libopencv-imgproc-dev:amd64     2.4.9.1+dfsg-2.1 libopencv-imgproc2.4v5:amd64    2.4.9.1+dfsg-2.1 libopencv-legacy2.4v5:amd64     2.4.9.1+dfsg-2.1 libopencv-ml2.4v5:amd64 2.4.9.1+dfsg-2.1 libopencv-objdetect2.4v5:amd64  2.4.9.1+dfsg-2.1 libopencv-video2.4v5:amd64      2.4.9.1+dfsg-2.1 libsigc++-2.0-0v5:amd64 2.8.0-2 libstdc++-4.9-dev:amd64 4.9.4-2ubuntu1 libstdc++-5-dev:amd64   5.4.1-2ubuntu2 libstdc++-6-dev:amd64   6.2.0-5ubuntu12 libstdc++6:amd64        6.2.0-5ubuntu12 libstdc++6:i386 6.2.0-5ubuntu12 

I use the following command to build the code:

g++ --std=c++14 test.cpp -lpthread -lopencv_highgui -lopencv_core -lopencv_imgproc -o test 

Valgrind outputs:

==18499== Thread 2: ==18499== Invalid read of size 8 ==18499==    at 0x690F0BA: ??? (in /usr/lib/x86_64-linux-gnu/libtbb.so.2) ==18499==    by 0x690F18A: ??? (in /usr/lib/x86_64-linux-gnu/libtbb.so.2) ==18499==    by 0x6910CE7: ??? (in /usr/lib/x86_64-linux-gnu/libtbb.so.2) ==18499==    by 0x690F691: ??? (in /usr/lib/x86_64-linux-gnu/libtbb.so.2) ==18499==    by 0x690A01F: ??? (in /usr/lib/x86_64-linux-gnu/libtbb.so.2) ==18499==    by 0x6908164: tbb::internal::allocate_root_with_context_proxy::allocate(unsigned long) const (in /usr/lib/x86_64-linux-gnu/libtbb.so.2) ==18499==    by 0x51D9E21: cv::parallel_for_(cv::Range const&, cv::ParallelLoopBody const&, double) (in /usr/lib/x86_64-linux-gnu/libopencv_core.so.2.4.9) ==18499==    by 0x55AE8A1: cv::remap(cv::_InputArray const&, cv::_OutputArray const&, cv::_InputArray const&, cv::_InputArray const&, int, int, cv::Scalar_<double> const&) (in /usr/lib/x86_64-linux-gnu/libopencv_imgproc.so.2.4.9) ==18499==    by 0x1094AC: run() (in /home/petr/osm/draw/test/test) ==18499==    by 0x10A360: void std::_Bind_simple<void (*())()>::_M_invoke<>(std::_Index_tuple<>) (in /home/petr/osm/draw/test/test) ==18499==    by 0x10A2ED: std::_Bind_simple<void (*())()>::operator()() (in /home/petr/osm/draw/test/test) ==18499==    by 0x10A2BD: std::thread::_State_impl<std::_Bind_simple<void (*())()> >::_M_run() (in /home/petr/osm/draw/test/test) ==18499==  Address 0xfffffffffffffff7 is not stack'd, malloc'd or (recently) free'd 

回答1:

OpenCV provides a parallel_for_ function that allows to easily parallel a portion of code using the parallel framework (Intel TBB, Pthreads, etc.) available on the computer.

It seems that in your case, the version of OpenCV you have is 2.4.9 with TBB used as the default parallel_for_ backend.

Here another issue with TBB called from multiple threads. The solution could be to disable TBB and use instead Pthreads (disable TBB and enable Pthreads in CMake) when building OpenCV from source.

Your solution should be fine also. With setNumThreads(0), the doc says:

If threads == 0, OpenCV will disable threading optimizations and run all it’s functions sequentially.

I guess that setNumThreads(1) should be fine also?

Unfortunately, I cannot determine exactly the source of the issue:

  • cv::remap is not thread safe in general or only with TBB?
  • an issue with the version of TBB? (not sure if this is related)
  • an issue with the version of OpenCV used?

I did two tests:

  • build OpenCV 3.2 from source on Ubuntu 16.04 with Pthreads used as parallel_for_ backend
  • build OpenCV 3.2 from source on Ubuntu 16.04 and use TBB instead

In both cases, I did not get any issues. So I hope it has been solved in newer OpenCV version or maybe in newer TBB version.

Note: you can use

std::cout << "getBuildInformation:\n" << cv::getBuildInformation() << std::endl;

to print the OpenCV information. In my second tests, I get:

Parallel framework: TBB (ver 4.4 interface 9003)



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!