いいえ、割り当てはスレッドセーフではありません。
2つのスレッドを作成するテストプログラムを作成しました。どちらも、cv :: Matを含むオブジェクトへのshared_ptrを含んでいます。あるスレッドはそのcv :: Matをランダムに生成されたイメージに割り当て、他のスレッドはそのcv :: Matのローカルコピーを作成します。
これは、ダブルフリーですぐにクラッシュします。コピースレッドがコピーを開始するときに書込みスレッドが前のものを上書きすると、削除されたばかりの内部データptrのcv :: Matをコピーします。コピー・スレッドのローカル・コピーが有効範囲外になると、そのコピーは再び解放されます。
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;
}
これはアトミックではないようです。 'if'はtrueを返し、コンテキスト切り替えが起こり、リリースと破壊が起こり、コンテキストスイッチバックとCV_XADDがsegfaultになります。 – Catskul
CV_XADDはアトミックなテスト・アンド・セットです(つまり、追加する前にrefcountをテストします)。最初の部分(refcountの場合)は、原子op状態に入る前に高速テスト用です。 – Sam
さらに、このコードは、わたしの知る限り、Googleの人たちによってリリースされています。私は彼らがそのような間違いをするとは思わない。 – Sam