2012-02-03 18 views
80

मैं http://gcc.gnu.org/onlinedocs/libstdc++/manual/shared_ptr.html पढ़ रहा हूँ के बारे में बताया और कुछ धागा सुरक्षा के मुद्दों अभी तक स्पष्ट मेरे लिए नहीं कर रहे हैं:std :: shared_ptr धागा सुरक्षा

  1. स्टैंडर्ड गारंटी देता है कि संदर्भ गिनती धागा सुरक्षित नियंत्रित किया जाता है और यह स्वतंत्र मंच है ना?
  2. इसी तरह की समस्या - मानक गारंटी देता है कि केवल एक धागा (अंतिम संदर्भ वाला होल्डिंग) साझा ऑब्जेक्ट पर हटाएगा, है ना?
  3. shared_ptr इसमें संग्रहीत वस्तु के लिए किसी भी थ्रेड सुरक्षा की गारंटी नहीं देता है?

संपादित करें:

छद्म कोड:

// Thread I 
shared_ptr<A> a (new A (1)); 

// Thread II 
shared_ptr<A> b (a); 

// Thread III 
shared_ptr<A> c (a); 

// Thread IV 
shared_ptr<A> d (a); 

d.reset (new A (10)); 

कॉलिंग रीसेट() धागा चतुर्थ में पहली धागा में बनाए गए एक वर्ग का पिछला उदाहरण हटा सकते हैं और नया उदाहरण से प्रतिस्थापित कर देगा? इसके अलावा चतुर्थ थ्रेड में रीसेट() को कॉल करने के बाद अन्य धागे केवल नव निर्मित वस्तु को देखेंगे?

+23

दाएं, दाएं और दाएं। – spraff

+14

आपको 'new' – qdii

उत्तर

67

के रूप में अन्य लोगों ने बताया है, तो आप इसे सही ढंग से अपने मूल 3 प्रश्न के बारे में पता लगा मिल गया है।

लेकिन अपने संपादित

धागा चतुर्थ में रीसेट() कॉलिंग पहले सूत्र में बनाई गई एक वर्ग का पिछला उदाहरण हटा सकते हैं और नया उदाहरण से प्रतिस्थापित कर देगा के अंतिम हिस्सा है? इसके अलावा चतुर्थ थ्रेड में रीसेट() को कॉल करने के बाद अन्य धागे केवल नव निर्मित वस्तु को देखेंगे?

सही नहीं है। केवल d नई A(10), और a, b को इंगित करेंगे, और c मूल A(1) को इंगित करने के लिए जारी रहेगा। इसे निम्नलिखित संक्षिप्त उदाहरण में स्पष्ट रूप से देखा जा सकता है। कि shared_ptr::reset() व्यवहार में शामिल नहीं किए जाते:

#include <memory> 
#include <iostream> 
using namespace std; 

struct A 
{ 
    int a; 
    A(int a) : a(a) {} 
}; 

int main(int argc, char **argv) 
{ 
    shared_ptr<A> a(new A(1)); 
    shared_ptr<A> b(a), c(a), d(a); 

    cout << "a: " << a->a << "\tb: " << b->a 
    << "\tc: " << c->a << "\td: " << d->a << endl; 

    d.reset(new A(10)); 

    cout << "a: " << a->a << "\tb: " << b->a 
    << "\tc: " << c->a << "\td: " << d->a << endl; 

    return 0;                           
} 

(जाहिर है, मैं किसी भी सूत्रण से परेशान नहीं किया।)

इस कोड के उत्पादन में

है एक: 1 ख: 1 c: 1 डी: 1

एक: 1 ख: 1 c: 1 d: 10

28
  1. सही है, shared_ptr परमाणु वेतन वृद्धि/एक संदर्भ गिनती मूल्य के decrements का उपयोग करें।

  2. मानक की गारंटी देता है केवल एक धागा एक साझा वस्तु पर नष्ट ऑपरेटर कॉल करेंगे। मुझे यकीन नहीं है कि क्या यह विशेष रूप से अंतिम थ्रेड निर्दिष्ट करता है जो साझा पॉइंटर की प्रतिलिपि हटा देता है वह वह होगा जो हटाएगा (संभवतः अभ्यास में यह मामला होगा)।

  3. नहीं वे नहीं है, यह में संग्रहीत वस्तु एक साथ कई धागे से संपादित किया जा सकता है।

संपादित करें: थोड़ा सा फॉलोअप, आप कैसे साझा संकेत सामान्य रूप में काम करते हैं की एक विचार आप boost::shared_ptr स्रोत को देखने के लिए चाहते हो सकता है पाने के लिए चाहते हैं: http://www.boost.org/doc/libs/1_37_0/boost/shared_ptr.hpp

+3

1 के बजाय' make_shared' का उपयोग करना चाहिए। जब ​​आप कहते हैं कि "shared_ptrs 'संदर्भ गणना मूल्य पर परमाणु वृद्धि/कमी का उपयोग करता है।" क्या आपका मतलब है कि वे परमाणु वृद्धि/कमी के लिए किसी आंतरिक लॉक का उपयोग नहीं करते हैं, जो संदर्भ स्विच करता है? सरल भाषा में लॉक का उपयोग किये बिना एकाधिक धागे बढ़ते/कमी संदर्भ गणना कर सकते हैं? एक परमाणु वृद्धि विशेष atomic_test_and_swap/atomic_test_and_increment निर्देशों द्वारा की जाती है? –

+0

@rahul संकलक एक म्यूटेक्स/लॉक का उपयोग करने के लिए स्वतंत्र है, लेकिन अधिकांश अच्छे कंपाइलर प्लेटफॉर्म पर म्यूटेक्स/लॉक का उपयोग नहीं करेंगे जहां इसे लॉक-फ्री किया जा सकता है। – Bernard

+0

@ बर्नार्ड: क्या आपका मतलब है कि यह मंच के लिए "compilers std lib shared_ptr" कार्यान्वयन पर निर्भर करता है? –

5

std :: shared_ptr थ्रेड सुरक्षित नहीं है।

एक साझा पॉइंटर दो पॉइंटर्स की एक जोड़ी है, ऑब्जेक्ट में से एक और एक नियंत्रण ब्लॉक में (रेफ काउंटर धारण करना, कमजोर पॉइंटर्स के लिंक ...)।

कई std :: shared_pointer हो सकते हैं और जब भी वे संदर्भ काउंटर को बदलने के लिए नियंत्रण ब्लॉक तक पहुंचते हैं तो यह थ्रेडसेफ है लेकिन "std :: shared_ptr" स्वयं थ्रेडसेफ या परमाणु नहीं है।

यदि आप किसी अन्य थ्रेड का उपयोग करते हुए std :: shared_pointer पर कोई नई ऑब्जेक्ट असाइन करते हैं, तो यह नया ऑब्जेक्ट पॉइंटर के साथ समाप्त हो सकता है लेकिन फिर भी पुराने ऑब्जेक्ट => CRASH के नियंत्रण ब्लॉक में पॉइंटर का उपयोग कर सकता है।

संबंधित मुद्दे