2010-11-24 14 views
9

लागू करने के लिए एक आवेदन मैं volatile चर, सैद्धांतिक रूप से इस्तेमाल किया multithreading के लिए मुफ्त कोड ताला: volatile कीवर्ड बस सुनिश्चित करें कि सभी धागे एक के सबसे अद्यतन मूल्य देख बनाने के लिए प्रयोग किया जाता है अस्थिर चर; इसलिए धागा A चर मूल्य अद्यतन करता है और धागा B पढ़ा है कि चर के तुरंत बाद कि अद्यतन हुआ है यह सबसे अद्यतन मूल्य के रूप में मैं संक्षेप किताब कि में एक सी # 4.0 में पढ़ा है कि धागा ए से हाल ही में लिखा देखेंगे अगर इस गलत क्योंकिवाष्पशील और सी # में Thread.MemoryBarrier

अस्थिर एक लिखने की अदला-बदली किए जाने से पढ़ने के बाद से नहीं रोकता है को लागू करने के लिए है।

इस समस्या volatile चर की तरह के हर से पहले Thread.MemoryBarrier() डाल द्वारा हल किया जा रहा किया जा सका:

private volatile bool _foo = false; 

private void A() 
{ 
    //… 
    Thread.MemoryBarrier(); 
    if (_foo) 
    { 
     //do somthing 
    } 
} 

private void B() 
{ 
    //… 
    _foo = true; 
    //… 
} 

और इस समस्या का हल है; मान लें कि हमारे पास थोड़ी देर लूप है जो उस मूल्य पर निर्भर करता है; जबकि लूप समस्या को ठीक करने का सही तरीका है, इससे पहले Thread.MemoryBarrier() डाल रहा है? उदाहरण:

private void A() 
{ 
    Thread.MemoryBarrier(); 
    while (_someOtherConditions && _foo) 
    { 
     // do somthing. 
    } 
} 

अधिक सटीक मैं _foo चर इसकी सबसे ताजा मूल्य जब किसी भी धागा इसे किसी भी समय के लिए पूछ देना चाहता हूँ होना करने के लिए; इसलिए Thread.MemoryBarrier() डालने से पहले चर बुला समस्या ठीक होती है तो मैं _foo के बजाय Foo संपत्ति का उपयोग करें और की है कि संपत्ति की तरह प्राप्त भीतर एक Thread.MemoryBarrier() कर सकता है यदि:

Foo 
{ 
    get 
    { 
     Thread.MemoryBarrier(); 
     return _foo; 
    } 
    set 
    { 
     _foo = value; 
    } 
} 
+0

संभावित डुप्लिकेट ... http: //stackoverflow.com/questions/1330590/when-to-use-volatile-or-thread-memorybarrier-in-threadsafe-locking-code-c –

+0

@Aron; नहीं, यह डुप्लिकेट नहीं है; यह एक और सवाल है। –

+0

@ जलाल क्या आप इस दृष्टिकोण अस्थिर/स्मृति बाधा का उपयोग कर किसी समस्या को हल करने का प्रयास कर रहे हैं या क्या आप अपनी समस्या हल करने वाले किसी भी दृष्टिकोण के साथ ठीक हैं? –

उत्तर

8

"सी # संक्षेप में" सही है, लेकिन इसका कथन मंथन है। क्यूं कर?

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

चलो स्पष्ट करें। अपने मूल कोड डालें:

private void A() 
{ 
    //… 
    if (_foo) 
    { 
     //do something 
    } 
} 

अगर धागा अनुसूचक पहले से ही _foo चर की जाँच की है, लेकिन यह सिर्फ //do something टिप्पणी से पहले निलंबित हो जाती है तो क्या होगा? खैर, उस बिंदु पर आपका अन्य धागा _foo के मान को बदल सकता है, जिसका अर्थ है कि आपके सभी अस्थिरताएं और थ्रेड। स्मृति बॉरियर्स कुछ भी नहीं गिने गए !!! यदि यह बिल्कुल जरूरी है कि do_something से बचा जाए तो _foo का मान गलत है, तो आपके पास लॉक का उपयोग करने के अलावा कोई विकल्प नहीं है।

हालांकि, अगर do something के लिए यह ठीक है तो _foo अचानक हो जाने पर निष्पादित होने के लिए ठीक है, तो इसका मतलब है कि अस्थिर कीवर्ड आपकी आवश्यकताओं के लिए पर्याप्त था।

स्पष्ट होने के लिए: सभी उत्तरदाता जो आपको स्मृति बाधा का उपयोग करने के लिए कह रहे हैं गलत हैं या ओवरकिल प्रदान कर रहे हैं।

+0

आपकी प्रतिक्रिया के लिए धन्यवाद; मेरे मामले में यदि मैं जितना संभव हो सके _foo सत्य था, तो मैं निष्पादित करने के लिए कुछ करना चाहता हूं, लेकिन यह ** घातक महत्वपूर्ण ** नहीं है; लेकिन अगर मैं इसे मेमोरीबैरियर के साथ और अधिक सटीक बना सकता हूं तो ** ** अस्थिरता के साथ इसका उपयोग क्यों नहीं करें .. यदि थ्रेड शेड्यूल _foo जांच के बाद थ्रेड को निलंबित करता है तो "चुड़ैल संभव है" तो do_somthing निष्पादित होगा लेकिन कम से कम हम ** संभावनाओं को कम करते हैं ** उस समय _foo गलत होगा? –

+2

@ जलाल: 'अस्थिर' घोषणा पहले से ही गौणियां हैं, सब कुछ स्वयं ही, कि चर एक सीपीयू रजिस्टर में संग्रहीत नहीं किया जाएगा। यह सीधे स्मृति पढ़ता है और लिखता है (जो एक बहु-प्रोसेसर मशीन पर अन्य प्रोसेसर के कैश को अमान्य करता है)। इसलिए स्पष्ट स्मृति बाधा अनावश्यक है; 'अस्थिर' पहले से ही आपको जो चाहिए वह पूरा कर रहा है। –

+0

@ ब्रेंटअरीस मेमोरीबैरियर * आवश्यक है क्योंकि प्रोसेसर के लिए एक प्रोसेसर पर मान अपडेट करना संभव है, न कि दूसरे पर एक धागा एक अद्यतन मान पढ़ता है और दूसरा धागा एक बालों का मान पढ़ता है। – Anthony

0

अपने दूसरे उदाहरण में, आप भी डाल करने की आवश्यकता होगी लूप के अंदर Thread.MemoryBarrier();, यह सुनिश्चित करने के लिए कि जब भी आप लूप स्थिति की जांच करते हैं तो आपको सबसे हालिया मूल्य मिलता है।

+0

यदि यह समस्या को हल करता है तो थ्रेड डालें। मेमरीबैरियर() को लूप के करीबी ब्रैकेट से पहले और लूप के कॉल से पहले अंतिम पंक्ति में होना चाहिए .. –

+0

@ जलाल: मैं काफी हद तक निश्चित हूं कि स्पष्ट 'मेमोरीबैरियर इन उदाहरणों में कॉल की आवश्यकता नहीं है, जब तक '_foo' को 'अस्थिर' के रूप में चिह्नित किया गया हो। (हालांकि मैं कोई विशेषज्ञ नहीं हूं; शायद मैं सिर्फ 'लॉक' का उपयोग करूंगा।) – LukeH

+2

इस मामले में: Thread.MemoryBarrier का उपयोग, चाहे पहले, बाद में, या दोनों, कुछ भी प्राप्त नहीं कर रहा है जो अस्थिर पहले से ही प्राप्त नहीं कर रहा था । –

0

here से खींचा ...

class Foo 
{ 
    int _answer; 
    bool _complete; 

    void A() 
    { 
    _answer = 123; 
    Thread.MemoryBarrier(); // Barrier 1 
    _complete = true; 
    Thread.MemoryBarrier(); // Barrier 2 
    } 

    void B() 
    { 
    Thread.MemoryBarrier(); // Barrier 3 
    if (_complete) 
    { 
     Thread.MemoryBarrier();  // Barrier 4 
     Console.WriteLine (_answer); 
    } 
    } 
} 

बाधाओं 1 और 4 "0" लिखने से इस उदाहरण को रोकने के। बाधाएं 2 और 3 ताजगी गारंटी प्रदान करते हैं: वे सुनिश्चित करते हैं कि यदि बी ए के बाद भाग गया, तो पढ़ना _complete सत्य का मूल्यांकन करेगा।

तो अगर हम अपने पाशन उदाहरण के लिए वापस जाओ ... यह है कि यह कैसे दिखना चाहिए है ...

private void A() 
{ 
    Thread.MemoryBarrier(); 
    while (_someOtherConditions && _foo) 
    { 
     //do somthing 
     Thread.MemoryBarrier(); 
    } 
} 
+1

@ हारून धन्यवाद, मैं उस लिंक को एक ही पुस्तक "सी # 4.0 में संक्षेप में" से पहले देखता हूं .. हालांकि अगर यह समस्या ठीक हो जाती है तो थ्रेड डालें। मेमरीबैरियर() को लूप के करीबी ब्रैकेट से पहले अंतिम पंक्ति में होना चाहिए । –

+0

@ जलाल यह निर्भर करता है कि आपका "कुछ करें" क्या करता है, जहां थ्रेडबैरियर बैठता है अब आपके _someOtherconditions/_foo vars –

+1

@Aaron को प्रभावित करता है: यदि '_foo' को 'अस्थिर' के रूप में चिह्नित किया गया है तो मुझे पूरा यकीन है कि स्पष्ट 'मेमोरीबैरियर' इन विशेष उदाहरणों में कॉल अनावश्यक हैं। (बहुत यकीन है लेकिन 100% निश्चित नहीं है, और यदि संदेह में है तो शायद मैं सिर्फ 'लॉक' का उपयोग करूंगा।) – LukeH

0

माइक्रोसॉफ्ट के स्मृति बाधाओं पर ही शब्दों:

MemoryBarrier केवल की आवश्यकता नहीं है कमजोर मेमोरी ऑर्डरिंग के साथ मल्टीप्रोसेसर सिस्टम (उदाहरण के लिए, एक इंटेल इटेनियम प्रोसेसर को नियोजित करने वाला एक सिस्टम)।

अधिकांश उद्देश्यों के लिए, सी # लॉक स्टेटमेंट, विजुअल बेसिक सिंकलॉक स्टेटमेंट, या मॉनिटर क्लास डेटा सिंक्रनाइज़ करने के आसान तरीके प्रदान करता है।

+0

कृपया यह देखने के लिए http://www.albahari.com/threading/part4.aspx देखें कि माइक्रोसॉफ्ट के अपने शब्द सही नहीं हैं !! –

+0

पोस्टर विशेष रूप से लॉक-फ्री कार्यान्वयन के लिए पूछ रहा है। –

5

पुस्तक सही है।
सीएलआर का मेमोरी मॉडल इंगित करता है कि लोड और स्टोर ऑपरेशंस को फिर से व्यवस्थित किया जा सकता है। यह अस्थिर और गैर-अस्थिर चर के लिए जाता है।

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

volatile का उपयोग अकेले कीवर्ड महत्वपूर्ण वर्ग नहीं बनाते हैं, और इससे धागे एक दूसरे के साथ जादुई रूप से सिंक्रनाइज़ नहीं होते हैं।

आपको लॉक फ्री कोड लिखते समय अत्यंत सावधान रहना चाहिए। इसके बारे में कुछ भी आसान नहीं है, और यहां तक ​​कि विशेषज्ञों को भी इसे सही करने में परेशानी है।
जो भी मूल समस्या आप हल करने की कोशिश कर रहे हैं, यह संभावना है कि ऐसा करने का एक और अधिक उचित तरीका है।

+0

@ लिरान: मुझे पता था कि अकेले अस्थिरता का उपयोग करने से महत्वपूर्ण वर्ग नहीं बनते हैं और न ही थ्रेड को एक-दूसरे के साथ सिंक्रनाइज़ करने का कारण बनता है .. मैं सिर्फ _foo वैरिएबल को अद्यतन मान के लिए पूछ रहा हूं जब कोई थ्रेड किसी भी समय इसके लिए पूछता है ताला मुफ्त कोड के भीतर। –

+0

@ जलाल, वैरिएबल को अस्थिर घोषित करने की गारंटी देगा कि प्रत्येक लोड ऑपरेशन चर के सबसे अद्यतन मूल्य को पढ़ेगा (उदा। रजिस्टर के बजाय मुख्य स्मृति से)। आपको अपने कोड पर मेमोरी बाधाओं को फैलाना नहीं चाहिए ... ऐसा करने से प्रदर्शन पर एक बड़ा नकारात्मक प्रभाव हो सकता है। दोबारा, यदि आप लॉक फ्री कोड के साथ खेलने और प्रयोग करने की कोशिश नहीं कर रहे हैं, और तस्वीर में असली, उत्पादन कोड है ... मैं आपको एक और समाधान खोजने के लिए प्रोत्साहित करता हूं। – Liran

+0

@ लिरान; "वैरिएबल को अस्थिर घोषित करने की गारंटी होगी कि प्रत्येक लोड ऑपरेशन चर के सबसे अद्यतन मूल्य को पढ़ेगा"; जैसा कि मैंने पुस्तक http://www.albahari.com/threading/part4.aspx से समझा है, जिसे पढ़कर अनुक्रमित किया गया है, शायद सबसे अद्यतन मूल्य प्राप्त नहीं हो सकता है, और हां, मैं लॉक फ्री कोड के साथ प्रयोग करने की कोशिश कर रहा हूं; सवाल यह है: क्या यह अस्थिर चर के किसी भी ऑपरेशन से पहले 'थ्रेड.मेमरीबैरियर' करते समय एप्लिकेशन के प्रदर्शन पर एक बड़ा नकारात्मक प्रभाव है, अगर यह वैरिएबल के किसी भी प्राप्त होने से पहले इसे किसी संपत्ति में नहीं डाल सकता है।कृपया प्रश्न अपडेट –

संबंधित मुद्दे