2012-05-18 18 views
5

मैं एक छवि साझा करने का प्रयास कर रहा हूं, जिसका उपयोग केवल धागे में ही पढ़ा जा रहा है। आमतौर पर मैं बूस्ट :: shared_ptrs के साथ इस तरह की चीज करता हूं लेकिन चूंकि सीवी :: मैट पहले से ही एक संदर्भ गिनती कंटेनर है, मैं इसे उसी तरीके से उपयोग करने का प्रयास कर रहा हूं, यह मानते हुए कि यह थ्रेड सुरक्षा के संदर्भों के आधार पर थ्रेड सुरक्षित है संदर्भ में यहां गिनती:सीवी :: मैट थ्रेड-सुरक्षित (परमाणु असाइनमेंट + refcounting) है?

हालांकि मैं गए होने समस्याएं यह संकेत दे संभवतः हो सकता है कि यह है कि वे वास्तव में कर रहे हैं सुरक्षित थ्रेड नहीं होने दिया; वह असाइनमेंट गैर-परमाणु है। कभी-कभी मुझे संदर्भ गणना वृद्धि के अंदर एक सीजी-गलती मिल जाएगी जिसका अर्थ है कि मूल वस्तु पहले से ही नष्ट हो चुकी है।

तो विशिष्ट सवाल यह है:

  • सीवी :: चटाई काम परमाणु है?

उत्तर

5

विशिष्ट प्रश्न, संक्षिप्त उत्तर: हाँ।

आप OpenCV स्रोतों से core/src/matrix.cpp और include/.../core/core.hpp

कुछ कोड अंश में सीवी :: चटाई कार्यान्वयन विवरण की जाँच कर सकते हैं:

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; 
} 

अतिरिक्त

स्मार्ट संकेत धागा सुरक्षा के स्तर की पेशकश करते हैं, लेकिन इसका मतलब यह नहीं है कि वे पूरी तरह से धागा सुरक्षित हर संभव स्थिति में हैं। विशेष रूप से, यदि आप एक ही समय में साझा पीआरटी की प्रतिलिपि बनाने का प्रयास करते हैं तो इसे किसी अन्य थ्रेड द्वारा नष्ट कर दिया जाता है, तो आप हार जाते हैं। यह कार्यान्वयन में एक बग नहीं है बल्कि गति और उपयोगिता के बीच एक डिजाइन व्यापार-बंद है।

सभी प्रमुख साझा पीआरटी कार्यान्वयन (बूस्ट, एसटीएल) इस दृष्टिकोण का पालन करते हैं।

+0

यह परमाणु प्रतीत नहीं होता है। 'If' सच हो सकता है, एक संदर्भ स्विच हो सकता है, एक रिलीज, और नष्ट हो सकता है, और फिर संदर्भ स्विच वापस और सीवी_एक्सएडीडी segfault होगा, जब तक कि मैं कुछ याद नहीं कर रहा हूँ। – Catskul

+0

सीवी_एक्सएडीडी एक परमाणु परीक्षण-और-सेट है (इसलिए, यह जोड़ने से पहले रीफॉउंट के लिए परीक्षण करता है)। परमाणु सेशन स्थिति में प्रवेश करने से पहले पहला भाग (यदि refcount) एक तेज परीक्षण के लिए है। – Sam

+0

इसके अलावा, जैसा कि मुझे पता है, यह कोड Google पर लोगों द्वारा जारी किया गया है।मुझे नहीं लगता कि वे ऐसी गलती करेंगे। – Sam

4

नहीं, असाइनमेंट पूरी तरह से थ्रेड सुरक्षित नहीं है।

मैंने एक परीक्षण कार्यक्रम लिखा जो दो धागे बनाता है। दोनों में एक ऑब्जेक्ट में shared_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; 
} 
संबंधित मुद्दे