क्या C # में एक बूल पढ़ना / लिखना परमाणु है


84

क्या C # में एक बूल क्षेत्र परमाणु तक पहुँच रहा है ? विशेष रूप से, क्या मुझे चारों ओर ताला लगाने की आवश्यकता है:

class Foo
{
   private bool _bar;

   //... in some function on any thread (or many threads)
   _bar = true;

   //... same for a read
   if (_bar) { ... }
}


1
हाँ, लेकिन (संभवतः) हाँ भी। हां, एक बूल क्षेत्र तक पहुंचना / स्थापित करना परमाणु है, लेकिन यदि ऑपरेशन नहीं है (नीचे दिए गए Dror Helper के उत्तर को देखें) तो आपको अभी भी लॉक की आवश्यकता हो सकती है।
जेपीप्रोग्रामर

जवाबों:


119

हाँ।

निम्नलिखित डेटा प्रकारों को पढ़ता और लिखता है परमाणु: बूल, चार, बाइट, सोबते, शॉर्ट, यूहोर्ट, यूंट, इंट, फ्लोट और संदर्भ प्रकार।

जैसा कि C # Language Spec में पाया गया है

संपादित करें: यह शायद अस्थिर कीवर्ड को समझने के लिए भी सार्थक है ।


10
सूचक ही, इसे पुन: सौंपता है, परमाणु है (यानी फू फू 1 = foo2;
उपयोगकर्ता 142350

4
@configurator: सवाल वही है जो आप चाहते हैं। ताला-मुक्त कार्यक्रमों को गलत करना आसान है; इसलिए जब तक आपको वास्तव में इसकी आवश्यकता नहीं होती है, यह एक सरल ढांचे (जैसे टीपीएल) का उपयोग करना बेहतर होता है। 'वाष्पशील' दूसरे शब्दों में गलत नहीं है, लेकिन मुश्किल (यानी अधिमान्य रूप से बचा हुआ) कोड का संकेत है। ओपी ने वास्तव में यह नहीं कहा कि वह क्या चाहता है, मैं अस्थिर विली-निली की सिफारिश करने में संकोच कर रहा हूं ।
Eamon Nerbonne

4
Waw। यह एक खतरनाक शब्द है, C ++ के लोगों के लिए परमाणु का मतलब है कि कोई भी पढ़ा लिखा भी संबंधित मेमोरी बाड़ से घिरा हुआ है। जो निश्चित रूप से C # में नहीं है। क्योंकि अन्यथा प्रदर्शन सभी चर के लिए अनिवार्य होने के बाद से भयानक होगा। यहाँ परमाणु # C # समता में, लगता है जब पढ़ने या लिखने के अंत में होने का मतलब है, वे एक टूटी हुई स्थिति में कभी नहीं होने की गारंटी है । लेकिन यह कुछ नहीं के रूप में जब "अंततः" है कहते हैं।
v.oddou

4
यदि int और long लिखना परमाणु है, तो कब उपयोग करें Interlocked.Add(ref myInt);?
माइक डी क्लार्क

6
@MikedeKlerk पढ़ने और लिखने के परमाणु, लेकिन अलग हैं। i++के बराबर है i=i+1, जिसका अर्थ है कि आप एक परमाणु पढ़ते हैं, फिर जोड़ते हैं, फिर परमाणु लिखते हैं। एक और धागा iपढ़ने के बाद लेकिन लिखने से पहले संशोधित किया जा सकता है । उदाहरण के लिए i++एक ही समय में समवर्ती दो सूत्र एक ही समय में पढ़ने के लिए हो सकते हैं (और इस तरह एक ही मूल्य पढ़ें), इसमें एक जोड़ें और फिर दोनों एक ही मूल्य लिखते हैं, प्रभावी रूप से केवल एक बार जोड़ते हैं। Interlocked.Add इसे रोकता है। एक सामान्य नियम के रूप में यह तथ्य है कि एक प्रकार परमाणु केवल तभी उपयोगी होता है जब केवल एक धागा लेखन हो, लेकिन कई सूत्र पढ़ने होते हैं।
जनीस फ्रॉइस

49

जैसा कि ऊपर कहा गया है कि परमाणु परमाणु है, लेकिन आपको अभी भी याद करने की आवश्यकता है कि यह इस पर भी निर्भर करता है कि आप इसके साथ क्या करना चाहते हैं।

if(b == false)
{
    //do something
}

परमाणु ऑपरेशन का अर्थ यह नहीं है कि यदि वर्तमान विवरण के बाद कोड थ्रेड निष्पादित करता है, तो b मान बदल सकता है।


29

बूल एक्सेस वास्तव में परमाणु हैं, लेकिन यह पूरी कहानी नहीं है।

आपको एक ऐसा मान पढ़ने की चिंता करने की ज़रूरत नहीं है जो 'अपूर्ण रूप से लिखा गया है' - यह स्पष्ट नहीं है कि किसी भी मामले में एक बूल के लिए संभवतः क्या मतलब हो सकता है - लेकिन आपको प्रोसेसर कैश के बारे में चिंता करने की ज़रूरत है, कम से कम यदि विवरण समय एक मुद्दा है। यदि कोर A पर चलने वाला # 1 _barकैश में है, और _barदूसरे कोर पर चलने वाले # 2 धागे से अपडेट हो जाता है, तो धागा # 1 तब तक बदलाव नहीं देखेगा जब तक कि आप लॉक करने की घोषणा नहीं _barकरते हैं volatile, या स्पष्ट रूप Thread.MemoryBarrier()से अमान्य करने के लिए कॉल सम्मिलित करें कैश्ड मान।


1
"यह स्पष्ट नहीं है कि संभवतः किसी भी मामले में एक बूल के लिए क्या मतलब हो सकता है" आइटम जो परमाणु में स्मृति के केवल एक बाइट में मौजूद हैं क्योंकि पूरे बाइट को एक ही समय में लिखा गया है। एकाधिक बाइट्स में वर्सस आइटम, जो कई बाइट्स में मौजूद हैं, एक बाइट दूसरे बाइट से पहले लिखी जा सकती है और आप आधे लिखित मेमोरी लोकेशन देख सकते हैं।
MindStalker

3
MemoryBarrier () किसी भी प्रोसेसर कैश को अमान्य नहीं करता है। कुछ आर्किटेक्चर में, प्रोसेसर को रीडर्स को फिर से लिखने और प्रदर्शन के लिए मुख्य मेमोरी में लिखने की अनुमति है। पुनरावृत्ति इतनी लंबी हो सकती है कि एक सूत्र के दृष्टिकोण से शब्दार्थ समान रहे। मैमोरीबैरियर () प्रोसेसर से अनुरोध करता है कि वह रीऑर्डरिंग को सीमित करे ताकि बैरियर से पहले निकलने वाले मेमोरी ऑपरेशंस को इस तरह से रीऑर्डर न किया जाए कि वे बैरियर के बाद खत्म हो जाएं।
टिमोच

1
एक मेमोरी बैरियर उपयोगी है यदि आप एक मोटी वस्तु बनाते हैं और इसके लिए एक संदर्भ स्विच करते हैं जो अन्य थ्रेड्स से पढ़ा जा सकता है। बाधा की गारंटी देता है कि संदर्भ वसा की शेष वस्तु से पहले मुख्य मेमोरी में अपडेट नहीं किया गया है। अन्य थ्रेड्स की गारंटी है कि वसा ऑब्जेक्ट वास्तव में मुख्य मेमोरी में उपलब्ध होने से पहले संदर्भ अद्यतन को कभी नहीं देखें। var fatObject = new FatObject(); Thread.MemoryBarrier(); _sharedRefToFat = fatObject;
टिआमोच

1

जिस दृष्टिकोण का मैंने उपयोग किया है, और मुझे लगता है कि सही है, है

volatile bool b = false;

.. rarely signal an update with a large state change...

lock b_lock
{
  b = true;
  //other;
}

... another thread ...

if(b)
{
    lock b_lock
    {
       if(b)
       {
           //other stuff
           b = false;
       }
     }
}

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


4
यह वास्तव में सामान्य रूप से लॉकिंग के लिए एक सही दृष्टिकोण है, लेकिन यदि बूल परमाणु हैं, तो लॉक को छोड़ना सरल (और तेज) है।
dbkk

2
ताला के बिना तब "बड़े राज्य परिवर्तन" को परमाणु रूप से नहीं किया जाएगा। ताला -> सेट | चेक -> लॉक -> चेक एप्रोच यह भी सुनिश्चित करेगा कि "// अन्य" कोड "// अन्य सामान" कोड से पहले निष्पादित हो। "एक और धागा" खंड मानकर कई बार (जो कि मेरे मामले में है) को परेशान कर रहा है, केवल एक बूल की जांच करने के लिए, ज्यादातर समय, लेकिन वास्तव में एक (संभवत:
संशोधित

1
ठीक है, अगर आपके पास है lock(), तो आपको ज़रूरत नहीं है volatile
xmedeko
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.