संदर्भ असाइनमेंट परमाणु है इसलिए इंटरलाक्ड। एक्सचेंज (रेफ ऑब्जेक्ट, ऑब्जेक्ट) की आवश्यकता क्यों है?


108

मेरी बहु ASMX वेब सेवा में मैं अपने ही प्रकार SystemData के एक वर्ग के क्षेत्र _allData कुछ के होते हैं जो था List<T>और Dictionary<T>के रूप में चिह्नित volatile। सिस्टम डेटा ( _allData) को एक बार में रिफ्रेश किया जाता है और मैं इसे एक और ऑब्जेक्ट बनाकर कॉल करता हूं newDataऔर इसे नए डेटा के साथ डेटा स्ट्रक्चर भरता हूं । जब यह हो जाए तो मैं अभी असाइन करूँ

private static volatile SystemData _allData

public static bool LoadAllSystemData()
{
    SystemData newData = new SystemData();
    /* fill newData with up-to-date data*/
     ...
    _allData = newData.
} 

असाइनमेंट के परमाणु होने के बाद से यह काम करना चाहिए और जिन थ्रेड्स में पुराने डेटा का संदर्भ है, वे इसका उपयोग करते रहते हैं और बाकी के पास असाइनमेंट के बाद नया सिस्टम डेटा होता है। हालाँकि मेरे कोलीगेट ने कहा कि volatileमुझे कीवर्ड और सरल एसिगमेंट का उपयोग करने के बजाय इसका उपयोग करना चाहिए InterLocked.Exchangeक्योंकि उन्होंने कहा कि कुछ प्लेटफार्मों पर यह गारंटी नहीं है कि संदर्भ असाइनमेंट परमाणु है। इसके अलावा: जब मैं घोषणा the _allDataके रूप में क्षेत्रvolatile

Interlocked.Exchange<SystemData>(ref _allData, newData); 

चेतावनी देता है "एक अस्थिर क्षेत्र के संदर्भ को अस्थिर नहीं माना जाएगा" मुझे इस बारे में क्या सोचना चाहिए?

जवाबों:


179

यहाँ कई सवाल हैं। एक समय में उन्हें एक माना जाता है:

संदर्भ असाइनमेंट परमाणु है इसलिए इंटरलाक्ड। एक्सचेंज (रेफ ऑब्जेक्ट, ऑब्जेक्ट) की आवश्यकता क्यों है?

संदर्भ असाइनमेंट परमाणु है। Interlocked.Exchange केवल संदर्भ असाइनमेंट नहीं करता है। यह एक चर के वर्तमान मूल्य का एक पाठ करता है, पुराने मूल्य को दूर करता है, और एक परमाणु संचालन के रूप में, चर को नया मूल्य प्रदान करता है।

मेरे सहयोगी ने कहा कि कुछ प्लेटफार्मों पर यह गारंटी नहीं है कि संदर्भ असाइनमेंट परमाणु है। क्या मेरा सहकर्मी सही था?

नहीं। संदर्भ असाइनमेंट सभी .NET प्लेटफॉर्म पर परमाणु होने की गारंटी है।

मेरा सहकर्मी झूठे परिसरों से तर्क कर रहा है। क्या इसका मतलब यह है कि उनके निष्कर्ष गलत हैं?

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

चेतावनी देता है "एक अस्थिर क्षेत्र के संदर्भ को अस्थिर नहीं माना जाएगा" मुझे इस बारे में क्या सोचना चाहिए?

आपको यह समझना चाहिए कि यह सामान्य रूप से समस्या क्यों है। इस बात की समझ पैदा होगी कि इस विशेष मामले में चेतावनी महत्वहीन क्यों है।

संकलक जो यह चेतावनी देता है उसका कारण यह है कि किसी क्षेत्र को अस्थिरता के रूप में चिह्नित करना "इस फ़ील्ड को कई थ्रेड पर अद्यतन किया जा रहा है - इस फ़ील्ड के मान को कैश करने वाला कोई कोड उत्पन्न न करें और सुनिश्चित करें कि कोई भी पढ़ता है या लिखता है यह क्षेत्र "समय से पहले और पीछे की ओर" प्रोसेसर कैश विसंगतियों के माध्यम से नहीं चला जाता है।

(मुझे लगता है कि आप वह सब कुछ पहले ही समझ गए हैं। यदि आपके पास अस्थिरता के अर्थ की विस्तृत समझ नहीं है और यह प्रोसेसर कैश शब्दार्थों को कैसे प्रभावित करता है तो आप यह नहीं समझते हैं कि यह कैसे काम करता है और इसे अस्थिर का उपयोग नहीं करना चाहिए। लॉक-फ्री प्रोग्राम। सही होना बहुत मुश्किल है; सुनिश्चित करें कि आपका कार्यक्रम सही है क्योंकि आप समझते हैं कि यह कैसे काम करता है, दुर्घटना से ठीक नहीं।)

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

इसलिए, जब आप ऐसा करते हैं तो संकलक चेतावनी देता है, क्योंकि यह संभवतः आपके ध्यान से विकसित लॉक-फ्री लॉजिक को पूरी तरह से गड़बड़ाने वाला है।

बेशक, Interlocked.Exchange है एक अस्थिर क्षेत्र उम्मीद को पत्र लिखा और सही काम। इसलिए चेतावनी भ्रामक है। मुझे इस बात का बहुत पछतावा है; हमें जो करना चाहिए था वह कुछ तंत्र को लागू कर रहा है जिससे इंटरलॉक की तरह एक विधि का एक लेखक। एक्सक्रॉज विधि पर एक विशेषता कह सकता है "यह विधि जो रेफरी के लिए अस्थिर शब्दार्थ को लागू करती है, इसलिए चेतावनी को दबाएं"। शायद संकलक के भविष्य के संस्करण में हम ऐसा करेंगे।


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

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

आपके उत्तर के लिए धन्यवाद एरिक। यह वास्तव में मेरी रुचि रखता है, इसीलिए मैं किताबों और ब्लॉगों को मल्टीथ्रेडिंग और लॉकिंग रणनीतियों के बारे में पढ़ रहा हूं और उन पर अपने कोड को लागू करने की कोशिश कर रहा हूं। लेकिन अभी भी बहुत कुछ सीखना
माइक

2
@EricLippert के बीच "मल्टीथ्रेडिंग का उपयोग न करें" और "यदि आपको आवश्यक है, अपरिवर्तनीय डेटा संरचनाओं का उपयोग करें", तो मैं मध्यवर्ती और बहुत ही सामान्य स्तर सम्मिलित करूंगा "एक बच्चे के थ्रेड का उपयोग केवल विशेष रूप से स्वामित्व वाली इनपुट ऑब्जेक्ट्स और माता-पिता के धागे के परिणामों का उपभोग करते हैं। केवल तभी जब बच्चा समाप्त हो गया हो ”। के रूप में var myresult = await Task.Factory.CreateNew(() => MyWork(exclusivelyLocalStuffOrValueTypeOrCopy));
जॉन

1
@ जॉन: यह एक अच्छा विचार है। मैं सस्ते प्रक्रियाओं की तरह थ्रेड्स का इलाज करने की कोशिश करता हूं: वे वहां एक कार्यक्रम करते हैं और परिणाम देते हैं, मुख्य कार्यक्रम के डेटा संरचनाओं के अंदर नियंत्रण का दूसरा धागा होने के आसपास नहीं चलाने के लिए। लेकिन अगर धागा जितना काम कर रहा है वह इतना बड़ा है कि इसे एक प्रक्रिया की तरह व्यवहार करना उचित है, तो मैं कहता हूं कि इसे एक प्रक्रिया बनाएं!
एरिक लिपर्ट

9

या तो आपके कोलीग को गलत माना जाता है, या वह कुछ ऐसा जानता है जो C # भाषा विनिर्देश नहीं करता है।

5.5 चर संदर्भों की परमाणु :

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

तो, आप दूषित मान प्राप्त करने के जोखिम के बिना अस्थिर संदर्भ में लिख सकते हैं।

आपको निश्चित रूप से सावधान रहना चाहिए कि आप कैसे तय करते हैं कि नए डेटा को कौन सा थ्रेड प्राप्त करना चाहिए, जो कि एक समय में एक से अधिक थ्रेड के जोखिम को कम करने के लिए।


3
@ गफ्फा: हां मैंने भी वही पढ़ा है। यह मूल प्रश्न छोड़ता है "संदर्भ असाइनमेंट परमाणु है इसलिए इंटरलॉक किया गया है। एक्सचेंज (रेफ ऑब्जेक्ट, ऑब्जेक्ट) की आवश्यकता है?" अनुत्तरित
char m

@ ज़ेराबॉक्स: तुम्हारा क्या मतलब है? जब वे नहीं हैं? तुम क्या करोगे?
चार

@ माटी: यह तब आवश्यक है जब आपको परमाणु ऑपरेशन के रूप में एक मूल्य पढ़ना और लिखना है।
गुफ़ा

.NET में वास्तव में मेमोरी को सही तरीके से संरेखित नहीं करने के बारे में आपको कितनी बार चिंता करनी है? इंटरोप-भारी सामान?
Skurmedel

1
@ ज़ेराबॉक्स: विनिर्देश उस चेतावनी को सूचीबद्ध नहीं करता है, यह एक बहुत स्पष्ट बयान देता है। क्या आपके पास एक गैर-मेमोरी-संरेखित स्थिति के लिए एक संदर्भ है जहां एक संदर्भ पढ़ा या लिखा हुआ परमाणु नहीं हो सकता है? ऐसा लगता है कि विनिर्देशन में बहुत स्पष्ट भाषा का उल्लंघन होगा।
टीजे क्राउडर

6

Interlocked.Exchange <T>

निर्दिष्ट प्रकार T के एक चर को एक निर्दिष्ट मान पर सेट करता है और एक परमाणु ऑपरेशन के रूप में मूल मान लौटाता है।

यह बदल जाता है और मूल मूल्य देता है, यह बेकार है क्योंकि आप केवल इसे बदलना चाहते हैं और, जैसा कि गुफ़ा ने कहा, यह पहले से ही परमाणु है।

जब तक एक प्रोफाइलर साबित नहीं करता है कि यह आपके आवेदन में एक अड़चन है, तो आपको ताला खोलने पर विचार करना चाहिए, यह समझना आसान है और यह साबित करना है कि आपका कोड सही है।


3

Iterlocked.Exchange() सिर्फ परमाणु नहीं है, यह स्मृति दृश्यता का भी ध्यान रखता है:

निम्नलिखित सिंक्रनाइज़ेशन फ़ंक्शंस मेमोरी ऑर्डर को सुनिश्चित करने के लिए उचित बाधाओं का उपयोग करते हैं:

महत्वपूर्ण अनुभागों में प्रवेश करने या छोड़ने वाले कार्य

सिंक्रनाइज़ेशन ऑब्जेक्ट्स को इंगित करने वाले फ़ंक्शंस

कार्यों की प्रतीक्षा करें

इंटरलॉक किए गए कार्य

सिंक्रनाइज़ेशन और मल्टीप्रोसेसर समस्याएँ

इसका मतलब यह है कि परमाणुता के अलावा यह सुनिश्चित करता है कि:

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