我正在尝试跨线程共享一个只用于只读的映像。通常我使用boost :: shared_ptrs做这种事情,但由于cv :: Mat已经是下面的引用计数容器,我一直试图以相同的方式使用它,假设它是基于对线程安全的引用的线程安全在这里引用计数:
但是我遇到的问题可能表明它们实际上并不是线程安全的;该任务是非原子的。偶尔我会在引用计数增量内得到一个seg-fault,这意味着原始对象已被破坏。
所以具体问题是:
答案 0 :(得分:5)
具体问题,简答:是的。
您可以在core/src/matrix.cpp
和include/.../core/core.hpp
OpenCV来源的一些代码摘录:
if( refcount )
CV_XADD(refcount, 1);
其中CV_XADD是原子测试和增量。
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;
}
<强>附加强>
智能指针确实提供了一定程度的线程安全性,但这并不意味着它们在每种情况下都是完全线程安全的。具体来说,如果您尝试复制共享ptr,同时它被另一个线程破坏,则会丢失。这不是实现中的错误,而是速度和实用性之间的设计权衡。
所有主要的共享ptr实现(boost,stl)都遵循这种方法。
答案 1 :(得分:5)
不,分配不是完全线程安全的。
我写了一个创建两个线程的测试程序。它们都包含一个包含cv :: Mat的对象的shared_ptr。一个线程将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;
}