Is cv :: Mat thread safe (atom assignment + refcounting)?

I am trying to share an image that is used for reading only by streams. I usually do such things with boost :: shared_ptrs, but since cv :: Mat is already a reference counting container under it, I try to use it in the same way, assuming it is thread safe based on the thread safety links in the link here:

However, I am having problems that may indicate that they are not thread safe; this assignment is not atomic. Sometimes I get a seg-fault inside the reference counter increment, which means that the original object has already been destroyed.

So the specific question is:

  • Is cv :: Mat an atom assignment?
+5
source share
2 answers

Specific question, short answer: YES.

You can check the implementation details of cv :: Mat in core/src/matrix.cppandinclude/.../core/core.hpp

Some snippets of code from OpenCV sources:

 if( refcount )
        CV_XADD(refcount, 1);

Where CV_XADD is the atomic test and increment.

inline void Mat::addref()
{ if( refcount ) CV_XADD(refcount, 1); }

inline void Mat::release()
{
    if( refcount && CV_XADD(refcount, -1) == 1 )
        deallocate();
    data = datastart = dataend = datalimit = 0;
    size.p[0] = 0;
    refcount = 0;
}

Extra

Smart pointers offer a level of thread safety, but this does not mean that they are completely thread safe in every scenario. In particular, if you try to copy the general ptr, at the same time it will be destroyed by another thread, you will lose. This is not a mistake in implementation, but a constructive compromise between speed and utility.

All major general implementations of ptr (boost, stl) follow this approach.

+5
source

No, an appointment is not an ideal stream.

, . shared_ptr , cv:: Mat. cv:: Mat , cv:: Mat.

. , , cv:: Mat, ptr . , .

volatile bool g_done = false;

struct Object
{
   cv::Mat cvMask;
};

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
void thread1(boost::shared_ptr<Object> sharedObj)
{
   while(!g_done)
   {
      sharedObj->cvMask = cv::Mat::ones(1 + (rand()% 1024), 1+(rand()%768), CV_8UC1);
   }
}

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
void thread2(boost::shared_ptr<Object> sharedObj)
{
   while(!g_done)
   {
      cv::Mat localCopy = sharedObj->cvMask;
   }
}

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
void sigHandler(int signum)
{
   fprintf(stderr, "Quitting...\n");
   g_done = true;
}

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
   signal(SIGINT, sigHandler);

   boost::shared_ptr<Object> sharedObj(new Object);
   sharedObj->cvMask = cv::Mat::ones(1024,768, CV_8UC1);

   boost::thread* t1 = new boost::thread(boost::bind(&thread1, _1), sharedObj);
   boost::thread* t2 = new boost::thread(boost::bind(&thread2, _1), sharedObj);

   while(!g_done)
   {
      usleep(1e6);
   }

   t1->join();
   t2->join();
   delete t1;
   delete t2;

   return 0;
}
+4

All Articles