2012-05-18 24 views
5

スレッド間で読み取り専用で使用されている画像を共有しようとしています。通常、私はboost :: shared_ptrsを使ってこのようなことをしますが、cv :: Matはすでに参照カウントのコンテナであるため、スレッド安全性への参照に基づいてスレッドセーフであると仮定して同じ方法で使用しようとしています参照してここにカウント:cv :: Matはスレッドセーフです(アトミック割り当て+ refcounting)?

私が持つ彼らは、スレッドセーフでないInfactはされていることを示している可能性があります問題を抱えてきたが、その割り当ては非アトミックです。場合によっては、元のオブジェクトが既に破棄されていることを意味する参照カウントの増分内にseg-faultが発生します。

だから具体的な質問です:

  • はCV ::マットの割り当ては、原子ますか?

答えて

5

特定の質問、短い答え:はい。

あなたはOpenCVのソースからのcore/src/matrix.cpp

include/.../core/core.hppいくつかのコードの抜粋でCV ::マットの実装の詳細を確認することができます。CV_XADDは原子テストとインクリメントをある

if(refcount) 
     CV_XADD(refcount, 1); 

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)はこのアプローチに従います。

+0

これはアトミックではないようです。 'if'はtrueを返し、コンテキスト切り替えが起こり、リリースと破壊が起こり、コンテキストスイッチバックとCV_XADDがsegfaultになります。 – Catskul

+0

CV_XADDはアトミックなテスト・アンド・セットです(つまり、追加する前にrefcountをテストします)。最初の部分(refcountの場合)は、原子op状態に入る前に高速テスト用です。 – Sam

+0

さらに、このコードは、わたしの知る限り、Googleの人たちによってリリースされています。私は彼らがそのような間違いをするとは思わない。 – Sam

4

いいえ、割り当てはスレッドセーフではありません。

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; 
} 
関連する問題