क्या C ++ 11 थ्रेड_लोकल वैरिएबल स्वचालित रूप से स्थिर हैं?


85

क्या इन दो कोड खंडों के बीच अंतर है:

void f() {
    thread_local vector<int> V;
    V.clear();
    ... // use V as a temporary variable
}

तथा

void f() {
    static thread_local vector<int> V;
    V.clear();
    ... // use V as a temporary variable
}

बैकस्टोरी: मूल रूप से मेरे पास एक स्टेटिक वेक्टर वी था (कुछ मध्यवर्ती मूल्यों को रखने के लिए, यह हर बार जब मैं समारोह में प्रवेश करता हूं) और एक एकल-थ्रेडेड प्रोग्राम को मंजूरी दे दी जाती है। मैं प्रोग्राम को एक मल्टीथ्रेडिंग में बदलना चाहता हूं, इसलिए किसी तरह मुझे इस स्थिर संशोधक से छुटकारा पाना है। मेरा विचार है कि हर स्थैतिक को थ्रेड_लोक में बदल दिया जाए और किसी और चीज की चिंता न की जाए? क्या यह दृष्टिकोण पीछे हो सकता है?


16
एक thread_localस्थानीय चर होने से कोई मतलब नहीं है ... प्रत्येक थ्रेड का अपना कॉल स्टैक होता है।
कोनराड रूडोल्फ

1
कई सी फ़ंक्शन मूल रूप से स्थिर या वैश्विक चर के पते को वापस करने के लिए लिखे गए थे। यह बाद में बहु-थ्रेडेड एप्लिकेशन (जैसे कि इरानो, स्थानीय समय) में उपयोग किए जाने पर अस्पष्ट बगों को जन्म देता है। इसके अलावा, कई बार म्यूटेक्स के साथ साझा चर की रक्षा करना बहुत हानिकारक होता है, जब किसी फ़ंक्शन को कई थ्रेड्स से कॉल किया जा रहा हो या कई कॉल ऑब्जेक्ट्स और विधियों के बीच थ्रेड संदर्भ ऑब्जेक्ट पास करना हो .. वेरिएबल्स जो थ्रेड हल करने के लिए स्थानीय हैं ये और अन्य मुद्दे।
edwinc

3
@ कोनराड रूडोल्फ स्थानीय चर की घोषणा करते हुए पूरी तरह से staticइसके बजाय static thread_localप्रत्येक थ्रेड के लिए चर के एक उदाहरण को इनिशियलाइज़ नहीं करता है।
davide

1
@ दाविद यह बात नहीं है, मैं या ओपी में से कोई भी। हम staticबनाम ( static thread_localबल्कि स्वचालित भंडारण) के पूर्व-सी ++ 11 अर्थ का उपयोग करते हुए autoबनाम के बारे में नहीं बल्कि बनाम के बारे में बात कर रहे हैं । thread_localauto
कोनराड रुडोल्फ

1
यह भी देखें कि थ्रेड-स्थानीय स्थानीय स्थिर चर को कैसे परिभाषित करें? । एक त्वरित भाषा वकील नोट ... विस्टा के आसपास माइक्रोसॉफ्ट और टीएलएस समर्थन बदल गया; देखें थ्रेड स्थानीय संग्रह (TLS) । यह परिवर्तन सिंगलटन जैसी चीजों को प्रभावित करता है और लागू हो भी सकता है और नहीं भी। यदि आप abondware सॉफ्टवेयर मॉडल का उपयोग कर रहे हैं तो आप शायद ठीक होंगे। यदि आप कई कंपाइलरों और प्लेटफार्मों का समर्थन करने में खुश हैं तो आपको इस पर ध्यान देना पड़ सकता है।
jww

जवाबों:


92

सी ++ मानक के अनुसार

जब थ्रेड_लोक को ब्लॉक स्कोप के एक वैरिएबल पर लागू किया जाता है, तो स्टोरेज-क्लास-स्पेसियर स्टैटिक को निहित किया जाता है यदि यह स्पष्ट रूप से प्रकट नहीं होता है

तो इसका मतलब है कि यह परिभाषा

void f() {
    thread_local vector<int> V;
    V.clear();
    ... // use V as a temporary variable
}

के बराबर है

void f() {
    static thread_local vector<int> V;
    V.clear();
    ... // use V as a temporary variable
}

हालाँकि, एक स्थिर चर, थ्रेड_लोक चर के समान नहीं है।

1 थ्रेड_लोकल कीवर्ड के साथ घोषित सभी वेरिएबल्स में थ्रेड स्टोरेज की अवधि होती है। इन संस्थाओं के लिए भंडारण उस थ्रेड की अवधि तक चलेगा जिसमें वे बनाए गए हैं। प्रति थ्रेड में एक अलग ऑब्जेक्ट या संदर्भ होता है, और घोषित नाम का उपयोग वर्तमान थ्रेड से जुड़ी इकाई को संदर्भित करता है

इन चरों को अलग करने के लिए स्टैण्डर्ड स्टोरेज अवधि के साथ मानक एक नई थ्रेड थ्रेड स्टोरेज अवधि का परिचय देता है ।


1
staticऔर externइस प्रकार स्टोरेज क्लास का मतलब नहीं है, लेकिन केवल आंतरिक स्कोप में भी थ्रेड_लोक वैरिएबल के लिए लिंकेज।
Deduplicator

4
@Deduplicator ब्लॉक स्कोप वैरिएबल का कोई लिंकेज नहीं है। तो आपका रिज्यूमे गलत है। जैसा कि मैंने पोस्ट में लिखा है कि उनके पास थ्रेड स्टोरेज की अवधि है। यह वास्तव में स्थिर भंडारण अवधि के समान है लेकिन प्रत्येक थ्रेड पर लागू होता है।
मास्को से व्लाद

1
यदि आप बाहरी जोड़ते हैं, तो आप एक घोषणा कर रहे हैं परिभाषा नहीं। इसलिए?
Deduplicator

1
@Deduplicator तो इसका मतलब है कि ब्लॉक स्कोप वैरिएबल की परिभाषाओं में कोई जुड़ाव नहीं है।
मास्को से व्लाद

1
मैंने अभी कोशिश की है कि वीएस 2013 में और यह चिल्लाता है "टीएल चर को गतिशील रूप से प्रारंभिक नहीं किया जा सकता है"। मैं चकरा गया हूं।
v.oddou

19

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


6

जब उपयोग किया जाता है thread_local, staticतो ब्लॉक-स्कोप में निहित होता है (देखें @ व्लाद का उत्तर), एक वर्ग के सदस्य के लिए आवश्यक; मेरा अनुमान है, नेमस्पेस स्कोप के लिए लिंकेज का मतलब है।

9.2 / 6 प्रति:

वर्ग परिभाषा के भीतर, किसी सदस्य को थ्रेड_लोकल स्टोरेज-क्लास-स्पेसियर के साथ घोषित नहीं किया जाएगा, जब तक कि उसे भी स्टैटिक घोषित नहीं किया जाता है

मूल प्रश्न का उत्तर देने के लिए:

क्या C ++ 11 थ्रेड_लोकल वैरिएबल स्वचालित रूप से स्थिर हैं?

नाम-स्थान-चर चर को छोड़कर कोई विकल्प नहीं है।

क्या इन दो कोड खंडों के बीच अंतर है:

नहीं।


4

थ्रेड लोकल स्टोरेज स्टैटिक है लेकिन यह सिंपल स्टैटिक स्टोरेज से काफी अलग है।

जब आप एक चर स्थैतिक की घोषणा करते हैं तो चर का एक उदाहरण होता है। कंपाइलर / रनटाइम सिस्टम गारंटी देता है कि यह आपके लिए वास्तव में उपयोग करने से पहले कुछ समय के लिए निर्दिष्ट किया जाएगा, जब वास्तव में निर्दिष्ट किए बिना (कुछ विवरण यहां छोड़ा गया है।)

C ++ 11 गारंटी देता है कि यह प्रारंभ थ्रेड सुरक्षित होगा, हालांकि C ++ 11 से पहले इस थ्रेड सुरक्षा की गारंटी नहीं थी। उदाहरण के लिए

static X * pointer = new X;

यदि एक ही समय में एक से अधिक स्टैटिक इनिशियलाइज़ेशन कोड हिट हो तो X के इंस्टेंस लीक हो सकते हैं।

जब आप एक वैरिएबल थ्रेड को स्थानीय घोषित करते हैं, तो वैरिएबल के कई उदाहरण हैं। आप उन्हें एक मानचित्र में होने के बारे में सोच सकते हैं जिसे थ्रेड-आईडी द्वारा अनुक्रमित किया गया था। इसका अर्थ है कि प्रत्येक थ्रेड चर की अपनी प्रति देखता है।

एक बार फिर, यदि वैरिएबल को इनिशियलाइज़ किया जाता है तो कंपाइलर / रनटाइम सिस्टम यह गारंटी देता है कि यह इनिशियलाइज़ेशन डेटा के उपयोग से पहले होगा और यह कि वैरिएशन वेरिएबल का उपयोग करने वाले प्रत्येक थ्रेड के लिए होगा। संकलक भी गारंटी देता है कि दीक्षा थ्रेड सुरक्षित होगी।

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


@ ईथरलोन: दिलचस्प। कौन सी विशेष जानकारी? क्या आप एक संदर्भ प्रदान कर सकते हैं?
डेल विल्सन

1
stackoverflow.com/a/8102145/1576556 । अगर मुझे सही याद है तो विकिपीडिया C ++ 11 लेख में इसका उल्लेख है।
Etherealone

1
हालांकि, स्थैतिक वस्तुओं को पहले आरंभीकृत किया जाता है, फिर असाइन की गई प्रतिलिपि। इसलिए मैं भी थोड़ा अस्पष्ट हूं कि क्या थ्रेड-सेफ इनिशियलाइज़ेशन में पूर्ण अभिव्यक्ति शामिल है। यह शायद इसलिए करता है क्योंकि अन्यथा इसे धागा-सुरक्षित नहीं माना जाएगा।
ईथरेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.