C ++ 11 में const का अर्थ थ्रेड-सेफ़ है?


115

मुझे लगता है कि सुनने के constसाधन धागा सुरक्षित में सी ++ 11 । क्या यह सच है?

इसका मतलब यह है constहै अब के बराबर जावा के synchronized?

क्या वे कीवर्ड से बाहर चल रहे हैं ?


1
C ++ - faq को आमतौर पर C ++ समुदाय द्वारा प्रशासित किया जाता है, और आप कृपया आकर हमसे हमारी चैट में राय पूछ सकते हैं।
पिल्ला

@DeadMG: मैं C ++ - faq और इसके शिष्टाचार से अनजान था, यह एक टिप्पणी में सुझाया गया था।
के-बैलो

2
आपने कहाँ सुना है कि कास्ट का मतलब थ्रेड-सेफ है?
मार्क बी

2
@ मर्क बी: हर्ब सटर और बज़्ने स्ट्रॉस्ट्रुप मानक सी ++ फाउंडेशन में ऐसा कह रहे थे , जवाब के नीचे लिंक देखें।
के-बैलो

उन लोगों के लिए नोट यहाँ आने: असली सवाल यह है कि नहीं है const का मतलब है धागा सुरक्षित। यह बकवास होगा, क्योंकि अन्यथा इसका मतलब होगा कि आपको आगे बढ़ने में सक्षम होना चाहिए और हर थ्रेड-सुरक्षित पद्धति को चिह्नित करना चाहिए const। बल्कि, जो सवाल हम वास्तव में पूछ रहे हैं वह const इम्प्लॉइज थ्रेड-सेफ है, और यही चर्चा है।
user541686

जवाबों:


131

मुझे लगता है कि सुनने के constसाधन धागा सुरक्षित में सी ++ 11 । क्या यह सच है?

यह कुछ हद तक है सही है ...

यह क्या है मानक भाषा धागे की सुरक्षा पर क्या कहना है:

[१.१० / ४] दो अभिव्यक्ति मूल्यांकन संघर्ष अगर उनमें से एक मेमोरी लोकेशन (१.)) को संशोधित करता है और दूसरा एक ही मेमोरी लोकेशन को एक्सेस या संशोधित करता है।

[१.१० / २१] एक कार्यक्रम के निष्पादन में एक डेटा रेस होती है, यदि इसमें विभिन्न थ्रेड्स में दो परस्पर विरोधी क्रियाएं होती हैं, जिनमें से कम से कम एक परमाणु नहीं है, और न ही दूसरे से पहले होता है। ऐसी किसी भी डेटा दौड़ के परिणाम अपरिभाषित व्यवहार में होते हैं।

डेटा रेस होने के लिए पर्याप्त स्थिति के अलावा और कुछ नहीं है:

  1. किसी दिए गए चीज़ पर एक ही समय में दो या अधिक क्रियाएं की जा रही हैं; तथा
  2. कम से कम उनमें से एक लेखन है।

स्टैंडर्ड लाइब्रेरी उस पर बनाता है, थोड़ा आगे जाने:

[१ [.६.५.९ / १] यह खंड उन आवश्यकताओं को निर्दिष्ट करता है जो क्रियान्वयन डेटा दौड़ (१.१०) को रोकने के लिए पूरा होगा। प्रत्येक मानक पुस्तकालय समारोह प्रत्येक आवश्यकता को पूरा करेगा जब तक कि अन्यथा निर्दिष्ट न हो। कार्यान्वयन नीचे निर्दिष्ट लोगों के अलावा अन्य मामलों में डेटा दौड़ को रोक सकता है।

[१ [.६.५.९ / ३] एक सी ++ मानक पुस्तकालय फ़ंक्शन प्रत्यक्ष या अप्रत्यक्ष रूप से वस्तुओं को (१.१०) वर्तमान धागे के अलावा अन्य थ्रेड द्वारा सुलभ नहीं करेगा, जब तक कि ऑब्जेक्ट सीधे या अप्रत्यक्ष रूप से फ़ंक्शन के नॉन- कॉस्ट तर्कोंके माध्यम से एक्सेस न होंthis

जो सरल शब्दों में कहता है कि यह अपेक्षा करता है कि constवस्तुओं पर संचालन थ्रेड-सुरक्षित होगा । इसका मतलब यह है कि मानक लाइब्रेरी तब तक डेटा रेस की शुरुआत नहीं करेगी, जब तक कि constआपके अपने प्रकार की वस्तुओं पर कार्रवाई नहीं होती है

  1. पूरी तरह से पढ़ता है - यह है, वहाँ कोई लिख रहे हैं -; या
  2. आंतरिक रूप से लिखता है।

यदि यह अपेक्षा आपके किसी एक प्रकार के लिए नहीं है, तो मानक पुस्तकालय के किसी भी घटक के साथ प्रत्यक्ष या अप्रत्यक्ष रूप से इसका उपयोग करने से डेटा रेस हो सकती है । अंत में, मानक पुस्तकालय बिंदु से थ्रेड-सेफ काconst मतलब है । यह ध्यान रखना महत्वपूर्ण है कि यह केवल एक अनुबंध है और इसे कंपाइलर द्वारा लागू नहीं किया जाएगा, यदि आप इसे तोड़ते हैं तो आपको अपरिभाषित व्यवहार मिलता है और आप अपने दम पर होते हैं। चाहे मौजूद है या कम से कम --at के संबंध में नहीं कोड पीढ़ी नहीं कोई असर नहीं पड़ेगा डेटा दौड़ -।const

इसका मतलब यह है constहै अब के बराबर जावा के synchronized?

नहीं । हर्गिज नहीं...

आयत का प्रतिनिधित्व करने वाले निम्न सरलीकृत वर्ग पर विचार करें:

class rect {
    int width = 0, height = 0;

public:
    /*...*/
    void set_size( int new_width, int new_height ) {
        width = new_width;
        height = new_height;
    }
    int area() const {
        return width * height;
    }
};

सदस्य-समारोह area है धागा सुरक्षित ; इसकी वजह से नहीं const, बल्कि इसलिए कि इसमें पूरी तरह से रीड ऑपरेशन शामिल हैं। इसमें कोई लेखन शामिल नहीं है, और डेटा दौड़ होने के लिए कम से कम एक लेखन शामिल होना आवश्यक है। इसका मतलब है कि आप कॉल कर सकते हैंarea जितने चाहें उतने धागे से हैं और आपको हर समय सही परिणाम मिलेंगे।

ध्यान दें कि यह है कि इसका मतलब यह नहीं rectहै धागा सुरक्षित । वास्तव में, यह देखना आसान है कि कैसे कॉल एक areaही समय में होने वाली थी कि set_sizeकिसी दिए गए कॉल पर rect, फिरarea पुरानी चौड़ाई और नई ऊंचाई (या यहां तक ​​कि विकृत मूल्यों पर आधारित) के आधार पर इसके परिणाम की गणना कर सकता है। ।

लेकिन यह है कि ठीक, rectनहीं है constतो इसकी भी होने के लिए नहीं की उम्मीद धागा सुरक्षित सब के बाद। const rectदूसरी ओर, घोषित की गई कोई वस्तु तब तक सुरक्षित रहेगी, जब तक कि कोई भी लेखन संभव नहीं है (और यदि आप const_castमूल रूप से घोषित की गई किसी चीज़ पर विचार कर रहे हैं, constतो आप अपरिभाषित व्यवहार प्राप्त करते हैं और ऐसा ही है)।

तो फिर इसका क्या मतलब है?

चलिए मान लेते हैं - तर्क की खातिर-- कि गुणन ऑपरेशन बेहद खर्चीले हैं और जब संभव हो तो हम बेहतर तरीके से उनसे बचते हैं। यदि अनुरोध किया जाता है, तो हम इस क्षेत्र की गणना कर सकते हैं और भविष्य में फिर से अनुरोध किए जाने पर इसे कैश कर सकते हैं:

class rect {
    int width = 0, height = 0;

    mutable int cached_area = 0;
    mutable bool cached_area_valid = true;

public:
    /*...*/
    void set_size( int new_width, int new_height ) {
        cached_area_valid = ( width == new_width && height == new_height );
        width = new_width;
        height = new_height;
    }
    int area() const {
        if( !cached_area_valid ) {
            cached_area = width;
            cached_area *= height;
            cached_area_valid = true;
        }
        return cached_area;
    }
};

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

सदस्य-समारोह area नहीं रह गया है धागे की सुरक्षित यह अब राईट कर रही है और आंतरिक रूप से संबद्ध नहीं है,। कोई समस्या है? कॉल किसी अन्य ऑब्जेक्ट के कॉपी-कंस्ट्रक्टर के areaहिस्से के रूप में हो सकता है , इस तरह के कंस्ट्रक्टर को एक मानक कंटेनर पर कुछ ऑपरेशन द्वारा बुलाया जा सकता था , और उस समय मानक लाइब्रेरी को उम्मीद है कि यह ऑपरेशन डेटा रेस के संबंध में रीड के रूप में व्यवहार करेगा। । लेकिन हम लिख रहे हैं!

जैसे ही हम rectएक मानक कंटेनर में डालते हैं - प्रत्यक्ष या अप्रत्यक्ष रूप से - हम मानक पुस्तकालय के साथ एक अनुबंध में प्रवेश कर रहे हैं । उस अनुबंध का सम्मान करते हुए भी एक फ़ंक्शन में लिखते रहना , हमें उन लेखों को आंतरिक रूप से सिंक्रनाइज़ करना होगा:const

class rect {
    int width = 0, height = 0;

    mutable std::mutex cache_mutex;
    mutable int cached_area = 0;
    mutable bool cached_area_valid = true;

public:
    /*...*/
    void set_size( int new_width, int new_height ) {
        if( new_width != width || new_height != height )
        {
            std::lock_guard< std::mutex > guard( cache_mutex );
        
            cached_area_valid = false;
        }
        width = new_width;
        height = new_height;
    }
    int area() const {
        std::lock_guard< std::mutex > guard( cache_mutex );
        
        if( !cached_area_valid ) {
            cached_area = width;
            cached_area *= height;
            cached_area_valid = true;
        }
        return cached_area;
    }
};

ध्यान दें कि हमने areaफ़ंक्शन को थ्रेड-सुरक्षित बनाया है , लेकिन फिर rectभी थ्रेड-सुरक्षित नहीं है । एक कॉल areaउसी समय हो रहा है कि एक कॉल set_sizeअभी भी गलत मान की गणना कर सकती है, क्योंकि असाइनमेंट म्यूटेक्स द्वारा संरक्षित widthऔर heightसंरक्षित नहीं हैं।

अगर हम वास्तव में एक धागा-तिजोरी चाहते थे rect , तो हम नॉन-थ्रेड-सेफ़ की सुरक्षा के लिए एक सिंक्रोनाइज़ेशन प्रिमिटिव का उपयोग करेंगे rect

क्या वे बाहर भाग रहे हैं? कीवर्ड से?

हाँ वे हैं। वे बाहर भागते रहे हैं दिन से ही कीवर्ड से हैं।


स्रोत : आप नहीं जानते constऔरmutable - हर्ब सटर


6
@Ben वोइट: यह मेरी समझ है कि सी ++ 11 के लिए विनिर्देश std::stringएक तरीका है कि पहले से ही मनाही में शब्दों है गाय । मुझे याद नहीं है, हालांकि, ...
K-ballo

3
@BenVoigt: नहीं, यह केवल ऐसी चीजों को अनसिंक्रनाइज़ होने से रोकेगा- यानी, थ्रेड सेफ नहीं। सी ++ 11 पहले से ही स्पष्ट रूप से प्रतिबंध लगाता है - इस विशेष मार्ग का उस से कोई लेना देना नहीं है, हालांकि, और गाय पर प्रतिबंध नहीं लगाएगा।
पिल्ला

2
यह मुझे लगता है कि एक तार्किक अंतर है। [१ [.६.५.९ / ३] ने "बहुत अधिक" यह कहकर मना किया "यह प्रत्यक्ष या अप्रत्यक्ष रूप से संशोधित नहीं होगा"; यह कहना चाहिए कि "प्रत्यक्ष या अप्रत्यक्ष रूप से एक डेटा दौड़ शुरू नहीं करेगा", जब तक कि एक परमाणु लेखन को कहीं भी "संशोधित" न होने के लिए परिभाषित किया गया हो। लेकिन मुझे यह कहीं भी नहीं मिल रहा है।
एंडी प्रोल

1
मैंने शायद अपने पूरे बिंदु को थोड़ा स्पष्ट कर दिया है: isocpp.org/blog/2012/12/… वैसे भी मदद करने के लिए धन्यवाद।
एंडी प्रोल

1
कभी-कभी मुझे आश्चर्य होता है कि इनमें से कौन था (या सीधे शामिल होने वाले) वास्तव में इन जैसे कुछ मानक पैराग्राफ लिखने के लिए जिम्मेदार हैं।
काली मिर्च_चिको
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.