我正在尝试跨线程共享一个图像,该图像仅以只读方式使用。通常我用 boost::shared_ptrs 做这种事情,但由于 cv::Mat 已经是下面的引用计数容器,我一直在尝试以相同的方式使用它,假设它是基于对线程安全的引用的线程安全的在此处的引用计数中:
但是我遇到的问题可能表明它们实际上不是线程安全的;该分配是非原子的。有时我会在引用计数增量中遇到段错误,这意味着原始对象已被销毁。
所以具体问题是:
不,分配不是完全线程安全的。
我写了一个创建两个线程的测试程序。它们都包含指向包含 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;
}
我是一名优秀的程序员,十分优秀!