std :: share_ptr थ्रेड सुरक्षा के बारे में बताया गया


106

मैं http://gcc.gnu.org/onbuildocs/libstdc++/manual/sared_ptr.html पढ़ रहा हूं और कुछ थ्रेड सुरक्षा मुद्दे अभी भी मेरे लिए स्पष्ट नहीं हैं:

  1. मानक गारंटी देता है कि संदर्भ गिनती धागा सुरक्षित है और यह प्लेटफ़ॉर्म स्वतंत्र है, है ना?
  2. इसी तरह का मुद्दा - मानक गारंटी देता है कि केवल एक धागा (पिछले संदर्भ को पकड़े हुए) साझा वस्तु पर कॉल हटाएगा, है ना?
  3. share_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));

थ्रेड IV में रीसेट () कॉल करने से पहले थ्रेड में बनाई गई A क्लास की पिछली आवृत्ति को हटा देगा और इसे नए इंस्टेंस के साथ बदल देगा? इसके अलावा IV थ्रेड में रीसेट () कॉल करने के बाद अन्य थ्रेड्स केवल नव निर्मित ऑब्जेक्ट देखेंगे?


24
सही, सही, और सही।
स्पैर्फ

16
आप के make_sharedबजाय का उपयोग करना चाहिएnew
qdii

जवाबों:


87

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

लेकिन आपके संपादन का अंतिम भाग

थ्रेड IV में रीसेट () कॉल करने से पहले थ्रेड में बनाई गई A क्लास की पिछली आवृत्ति को हटा देगा और इसे नए इंस्टेंस के साथ बदल देगा? इसके अलावा IV थ्रेड में रीसेट () कॉल करने के बाद अन्य थ्रेड्स केवल नव निर्मित ऑब्जेक्ट देखेंगे?

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

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

(स्पष्ट रूप से, मैं किसी भी थ्रेडिंग से परेशान नहीं था: जो shared_ptr::reset()व्यवहार में कारक नहीं है।)

इस कोड का आउटपुट है

a: 1 b: 1 c: 1 d: 1

a: 1 b: 1 c: 1 d: 10


35
  1. सही, shared_ptrएक संदर्भ संख्या मान के परमाणु वेतन वृद्धि / घटाव का उपयोग करें।

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

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

संपादित करें: यदि आप सामान्य रूप से साझा किए गए पॉइंटर्स के बारे में जानना चाहते हैं, तो आप इस boost::shared_ptrस्रोत को देखना चाहते हैं : http://www.boost.org/doc/libs/1_37_0/boost/sared_nr.hpp


3
1. जब आप कहते हैं "" साझा_प्रकार 'संदर्भ संख्या मान के परमाणु वृद्धि / घटाव का उपयोग करते हैं। " क्या आपका मतलब है कि वे परमाणु वृद्धि / वृद्धि के लिए किसी भी आंतरिक लॉक का उपयोग नहीं करते हैं, जो संदर्भ स्विच करता है? सरल भाषा में कई थ्रेड्स लॉक का उपयोग किए बिना इंक्रीमेंट / डिक्रीमेंट रेफरेंस काउंट बढ़ा सकते हैं? परमाणु वृद्धि विशेष परमाणु_ तंत्र_वापस / परमाणु / परमाणु_और_संक्रमण निर्देश द्वारा की जाती है?
rahul.deshmukhpatil

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

@ बर्नार्ड: क्या इसका मतलब यह है कि यह प्लेटफॉर्म के लिए "कंपाइलर्स एसटीडी लिबर शेयर्ड_प्ट्र" कार्यान्वयन पर निर्भर करता है?
rahul.deshmukhpatil

2
हाँ। मेरी समझ से, मानक यह नहीं कहता है कि इसे लॉक-फ़्री होना चाहिए। लेकिन नवीनतम जीसीसी और एमएसवीसी में, यह इंटेल x86 हार्डवेयर पर लॉक-फ्री है, और मुझे लगता है कि हार्डवेयर का समर्थन करने पर अन्य अच्छे संकलक भी ऐसा करने की संभावना रखते हैं।
बर्नार्ड

18

std::shared_ptr धागा सुरक्षित नहीं है।

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

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

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


4
हम कह सकते हैं कि एकल std::shared_ptrउदाहरण थ्रेड सुरक्षित नहीं है। एसटीडी से: साझा किया गया साझा संदर्भ:If multiple threads of execution access the same shared_ptr without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur;
जेकेवल्स्की

इसे बेहतर तरीके से शब्दबद्ध किया जा सकता था। एक std::shared_ptr<T>धागा की गारंटी थ्रेड-सेफ है जब हमेशा थ्रेड सीमाओं के पार मूल्य (कॉपी / मूव) द्वारा उपयोग किया जाता है । अन्य सभी उपयोग, std::shared_ptr<T>&धागा सीमाओं के पार असुरक्षित हैं
WhiZTiM
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.