2009-08-03 5 views
39

आइए बस कहें कि आपके पास एक साधारण ऑपरेशन है जो पृष्ठभूमि थ्रेड पर चलता है। आप इस ऑपरेशन को रद्द करने का एक तरीका प्रदान करना चाहते हैं ताकि आप एक बुलियन ध्वज बना सकें जिसे आपने रद्द बटन के क्लिक ईवेंट हैंडलर से सही पर सेट किया है।क्या मुझे सी # में एक साधारण बूलियन ध्वज तक पहुंचने पर अस्थिर के रूप में लॉक या चिह्नित करने की आवश्यकता है?

private bool _cancelled; 

private void CancelButton_Click(Object sender ClickEventArgs e) 
{ 
    _cancelled = true; 
} 

अब आप GUI थ्रेड से रद्द ध्वज सेट कर रहे हैं, लेकिन आप इसे पृष्ठभूमि थ्रेड से पढ़ रहे हैं। क्या आपको बूल तक पहुंचने से पहले लॉक करने की ज़रूरत है?

आप ऐसा करने (और स्पष्ट रूप से बटन क्लिक ईवेंट हैंडलर में भी ताला) की जरूरत है चाहेंगे:

while(operationNotComplete) 
{ 
    // Do complex operation 

    lock(_lockObject) 
    { 
     if(_cancelled) 
     { 
      break; 
     } 
    } 
} 

या यह स्वीकार्य (कोई लॉक के साथ) यह करने के लिए है:

while(!_cancelled & operationNotComplete) 
{ 
    // Do complex operation 
} 

या _cancelled चर को अस्थिर के रूप में चिह्नित करने के बारे में क्या। क्या यह आवश्यक है?

[मुझे पता है कि इसके अंतर्निहित CancelAsync() विधि के साथ पृष्ठभूमिवर्कर वर्ग है, लेकिन मुझे अर्थशास्त्र में दिलचस्पी है और लॉकिंग और थ्रेडेड वैरिएबल एक्सेस का उपयोग यहां नहीं है, विशिष्ट कार्यान्वयन नहीं, कोड सिर्फ एक उदाहरण है। ]

दो सिद्धांतों के रूप में प्रतीत होता है।

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

सही तकनीक कौन सा है? (और क्यों?)

[संपादित करें: इस पर विचार के दो स्पष्ट रूप से परिभाषित और विरोध करने वाले स्कूल प्रतीत होते हैं। मैं इस पर एक निश्चित उत्तर ढूंढ रहा हूं, इसलिए यदि संभव हो तो अपने कारणों को पोस्ट करें और अपने उत्तर के साथ अपने स्रोतों का हवाला दें।]

+6

हां, आपको * या तो 'अस्थिर' या 'लॉक' (स्मृति बाधा के रूप में कार्य करने के लिए) की आवश्यकता है: http://stackoverflow.com/questions/458173/can-ac-thread-really-cache- एक-मूल्य-और-अनदेखा-परिवर्तन-से-मूल्य-पर-अन्य-वें/458193 # 458193 –

+1

क्या इसका मतलब यह है कि साइमन को द्रव्यमान बहस में लाल चेहरे का सामना करना पड़ रहा है, जिसमें वह ईफ्राइम (http : //stackoverflow.com/questions/1221839/c-break-out-of-loop-on-button-press/1221854#1221854) – ThePower

+1

@Marc: अच्छा उदाहरण, धन्यवाद। @ThePower: मुझे यकीन नहीं है कि मैं अपने हाथों को ऊपर रखकर खुश हूं, इसलिए उम्मीद है कि मैं केवल हल्के गुलाबी चेहरे से बच जाऊंगा = :) –

उत्तर

31

सबसे पहले, थ्रेडिंग, मुश्किल ;-p

हाँ, विपरीत करने के लिए सभी अफवाहों के बावजूद है यह को या तो उपयोग की आवश्यकता है lockयाvolatile (लेकिन दोनों) जब एक bool तक पहुँचने एकाधिक धागे से।

सरल प्रकार और एक्सेस जैसे फ्लैग (bool) के लिए, volatile पर्याप्त है - यह सुनिश्चित करता है कि धागे उनके रजिस्टरों में मान कैश न करें (अर्थ: धागे में से कोई भी अद्यतन कभी नहीं देखता)।

बड़े मान (जहां atomicity एक मुद्दा है) के लिए

, या जहाँ आप एक क्रम के संचालन की (एक विशिष्ट उदाहरण जा रहा है "नहीं तो मौजूद है और जोड़ें" पहुँच शब्दकोश) सिंक्रनाइज़ करना चाहते हैं, एक lock अधिक बहुमुखी है। यह स्मृति-बाधा के रूप में कार्य करता है, इसलिए आपको थ्रेड सुरक्षा देता है, लेकिन अन्य सुविधाओं जैसे नाड़ी/प्रतीक्षा प्रदान करता है। ध्यान दें कि आपको मूल्य-प्रकार या string पर lock का उपयोग नहीं करना चाहिए; न ही Type या this; सबसे अच्छा विकल्प है कि आप अपनी लॉकिंग ऑब्जेक्ट को फ़ील्ड (readonly object syncLock = new object();) के रूप में रखें और इसे लॉक करें।

यदि आप सिंक्रनाइज़ नहीं करते हैं तो यह कितना बुरी तरह टूटता है (यानी हमेशा के लिए लूपिंग) उदाहरण के लिए - see here

एकाधिक प्रोग्रामों को विस्तारित करने के लिए, Mutex या *ResetEvent जैसे ओएस आदिम भी उपयोगी हो सकते हैं, लेकिन यह एक exeill के लिए अधिक है।

+0

मुझे लगता है कि यह इस मुद्दे को सुलझता है।यदि आप लॉक या अस्थिरता का उपयोग नहीं करते हैं तो यह एक पुन: उत्पन्न उदाहरण है कि यह गलत कैसे हो सकता है। –

+0

@ मार्कग्रावेल ♦ क्या कोई संभावना है कि 2 थ्रेड एक ही समय में अस्थिर चर को लिखते हैं? – onmyway133

+0

@entropy हाँ, इसे रोकने के लिए कुछ भी नहीं है। मूल्यों में से एक जीत जाएगा; यह परिभाषित नहीं किया गया है कि कौन सा है। ध्यान दें कि कंपाइलर केवल आपको 'वाष्पशील' का उपयोग उन प्रकारों के साथ करने देता है जिन्हें परमाणु रूप से लिखा जा सकता है, इसलिए आप एक टूटे हुए मूल्य के साथ समाप्त नहीं होंगे –

6

_cancelledvolatile होना चाहिए। (यदि आप लॉक करना नहीं चुनते हैं)

यदि कोई थ्रेड _cancelled के मान को बदलता है, तो अन्य थ्रेड अपडेट किए गए परिणाम को नहीं देख सकते हैं।

इसके अलावा, मुझे लगता है कि _cancelled की पढ़ें/लिखें संचालन परमाणु हैं:

CLI कल्पना राज्यों की धारा 12.6.6: "एक अनुरूप CLI कि पढ़ने की गारंटी और लिखने की एक्सेस करेगा ठीक से गठबंधन मेमोरी स्थानों को देशी शब्द आकार की तुलना में परमाणु पर सभी लिखने पर स्थान का उपयोग समान आकार है। "

+0

@ मिच: लेकिन इस मामले में इसका मतलब है कि यह चीजों को पेंच कर सकता है। – EFraim

+0

बस सुधार के बिंदु के रूप में, लॉकिंग का कोई प्रभाव नहीं होगा कि किसी चर को पढ़ने या लिखने के लिए कैश किया गया है या नहीं। लॉकिंग एक अस्थिर चर के लिए एक प्रतिस्थापन नहीं है। –

+0

परमाणुता के साथ इसके साथ बहुत कुछ नहीं करना है ... यदि अन्य धागा अभी भी अपने रजिस्टरों पर चबाने वाला है तो यह शून्य अंतर बनाता है चाहे आप 1 खंड में या 26 में मान लिखें। –

2

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

private System.Threading.ManualResetEvent threadStop; 

void StartThread() 
{ 
    // do your setup 

    // instantiate it unset 
    threadStop = new System.Threading.ManualResetEvent(false); 

    // start the thread 
} 

अपने धागा में ..

while(!threadStop.WaitOne(0) && !operationComplete) 
{ 
    // work 
} 
जीयूआई को रद्द करने में

फिर ...

threadStop.Set(); 
+0

एक ओएस आदिम आमतौर पर एक ऐप, आईएमओ के लिए ओवरकिल होता है। ज्यादातर चीजें सिर्फ 'मॉनिटर' के साथ की जा सकती हैं। –

+0

@Marc: जबकि * * ResetEvent को यहां स्पष्ट रूप से आवश्यक नहीं हो सकता है, मुझे नहीं लगता कि मैं यह कहने को तैयार हूं कि यह एक ही एप्लिकेशन के लिए अधिक है। ऐसे कई उदाहरण हैं जहां एक एप्लिकेशन के भीतर एकाधिक थ्रेड को EventRetetEvent जैसे EventWaitHandle की कार्यक्षमता का उपयोग करने की आवश्यकता हो सकती है। –

1

देखो Interlocked.Exchange() ऊपर। यह एक स्थानीय चर में एक बहुत तेज प्रतिलिपि बनाता है जिसका उपयोग तुलना के लिए किया जा सकता है। यह ताला() से तेज है।

+0

यह गति विचार नहीं है; यह सहीता है .... –

+0

+1, हमेशा सर्वश्रेष्ठ नहीं है लेकिन यह तीनों में से एक है (लॉक/इंटरलाक्ड/अस्थिर) संभावनाएं। –

+0

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

5

लॉकिंग की आवश्यकता नहीं है क्योंकि आपके पास एक एकल लेखक परिदृश्य है और एक बुलियन फ़ील्ड एक साधारण संरचना है जिसमें राज्य को भ्रष्ट करने का कोई जोखिम नहीं है (while it was possible to get a boolean value that is neither false nor true)। लेकिन संकलक को कुछ अनुकूलन करने से रोकने के लिए आपको फ़ील्ड को volatile के रूप में चिह्नित करना होगा। volatile संशोधक के बिना कंपाइलर आपके कार्यकर्ता धागे पर आपके लूप के निष्पादन के दौरान एक रजिस्टर में मान को कैश कर सकता है और बदले में लूप परिवर्तित मूल्य को कभी पहचान नहीं पाएगा। यह एमएसडीएन आलेख (How to: Create and Terminate Threads (C# Programming Guide)) इस समस्या को संबोधित करता है। लॉकिंग की आवश्यकता होने पर, लॉक volatile फ़ील्ड को चिह्नित करने के समान प्रभाव डालेगा।

+0

यह सही है। चूंकि आप या तो इस ध्वज के मूल्य को पढ़ या सेट करते हैं, इसलिए आपको केवल 'अस्थिर' विशेषता है। – jpbochi

+0

लेकिन सिद्धांत में यदि आप बुलियन क्षेत्र का अद्यतन परमाणु नहीं हैं और आंशिक अद्यतन परिणाम उस मान में नहीं हैं जो न तो सत्य है और न ही गलत है, लेकिन इससे उपयोग किए गए उपयोग परिदृश्य में कोई समस्या नहीं होगी। –

+0

@Daniel - एक बूल अपडेट spec द्वारा परमाणु होने की गारंटी है। –

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

  • कोई संबंधित समस्या नहीं^_^