2012-08-14 13 views
12

मेरे पास एक कार्यकर्ता थ्रेड में कोई ऑब्जेक्ट है, जिसे मैं चलाना बंद करने के लिए निर्देश दे सकता हूं। मैं इस एक bool या एक AutoResetEvent का उपयोग कर लागू कर सकते हैं:ऑटो रीसेट इवेंट बनाम बूलियन थ्रेड को रोकने के लिए

बूलियन:

private volatile bool _isRunning; 

public void Run() { 
    while (_isRunning) 
    { 
     doWork(); 
     Thread.Sleep(1000); 
    } 
} 

AutoResetEvent:

private AutoResetEvent _stop; 

public void Run() { 
    do { 
     doWork(); 
    } while (!_stop.WaitOne(1000)); 
} 

Stop() विधि तो गलत पर _isRunning सेट होता है, या _stop.Set() कहते हैं।

इसके अलावा ऑटोरसेट के साथ समाधान थोड़ा तेज़ हो सकता है, क्या इन तरीकों के बीच कोई अंतर है? क्या यह दूसरे से बढ़िया है?

+2

मैं सोने के बजाए टाइमर का उपयोग करूंगा। इसे समाप्त करने के लिए, आप बस टाइमर को रोक सकते हैं। – Servy

+0

मैंने जवाब देने के लिए कुछ अवलोकन जोड़ दिए हैं, मूल रूप से मुझे नहीं लगता कि ये स्निपेट आप जो चाहते हैं वह करते हैं। – Jodrell

उत्तर

11

सी # अस्थिर सभी गारंटी प्रदान नहीं करता है। यह अभी भी पुराना डेटा पढ़ सकता है। अंतर्निहित ओएस सिंक्रनाइज़ेशन तंत्र का उपयोग करने के लिए बेहतर है क्योंकि यह बहुत मजबूत गारंटी प्रदान करता है।

सभी इस एरिक Lippert (वास्तव में लायक पढ़ने) द्वारा महान गहराई discussed में, यहाँ कम उद्धरण है:

सी # में, "अस्थिर" न केवल "यह सुनिश्चित कर लें मतलब यह है कि संकलक और घबराना इस चर " पर किसी भी कोड रीडरिंग या कैशिंग अनुकूलन पंजीकृत न करें।इसका अर्थ यह भी है कि "प्रोसेसर को पर बताएं कि यह सुनिश्चित करने के लिए कि उन्हें नवीनतम मान पढ़ रहा है, भले ही इसका मतलब है कि अन्य प्रोसेसर को रोकना और बनाना उनके मुख्य कैश को उनके कैश" "के साथ सिंक्रनाइज़ करना है।

असल में, आखिरी बिट झूठ है। अस्थिरता के वास्तविक अर्थशास्त्र पढ़ते हैं और लिखते हैं कि मैंने यहां उल्लिखित की तुलना में काफी जटिल हैं; तथ्य वे वास्तव में गारंटी नहीं देते हैं कि प्रत्येक प्रोसेसर कर रहा है और मुख्य स्मृति से/कैश अपडेट करता है। इसके बजाय, वे को कमजोर गारंटी देते हैं कि स्मृति के पहले और बाद में कैसे उपयोग किया जाता है और लिखने को एक-दूसरे के संबंध में आदेश दिया जा सकता है। कुछ नए ऑपरेशन जैसे लॉक में प्रवेश करना, लॉक में प्रवेश करना, या इंटरलॉक परिवारों में से एक का उपयोग करके मजबूत संचालन ऑर्डरिंग के अवलोकन के बारे में गारंटी देता है। यदि आप अधिक जानकारी चाहते हैं, तो सी # 4.0 विनिर्देश के अनुभाग 3.10 और 10.5.3 पढ़ें।

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

+0

+1 क्योंकि यह मेरे पहले बिंदु को अधिक विस्तार से दोहराता है – Jodrell

+0

अस्थिर काम ठीक है। किसी भी धागे को लिखने के लिए सभी मेमोरी अपडेट मुख्य मेमोरी में धकेल जाते हैं। किसी भी धागे को पढ़ने से इसकी वर्किंग मेमोरी मुख्य से ताज़ा हो जाती है। इसलिए एक अस्थिर (और जिस डेटा का संदर्भ है) को _write_ उस अस्थिर से किसी भी _read_ द्वारा देखा जाएगा। उस ने कहा, इस मामले में ऑटोरेटेवेंट मेरे लिए बहुत बेहतर दिखता है। एक मल्टीप्रोसेसर सिस्टम पर – RalphChapin

+1

@ राल्फचैपिन AFAIK केवल * कमजोर * गारंटी है कि * सभी * प्रोसेसर एक अद्यतन मूल्य देखेंगे। – oleksii

3

IMHO AutoResetEvent बेहतर है, क्योंकि आप इस मामले में महत्वपूर्ण volatile कीवर्ड को नहीं भूल सकते हैं।

0

यह निर्भर करता है कि उपरोक्त स्निपेट आप सब कुछ कर रहे हैं या नहीं। ऑटोरसेट घटना, जैसा कि इसके नाम से पता चलता है, वेटऑन पास होने के बाद रीसेट हो जाता है। इसका मतलब यह है कि आप इसे फिर से सही तरीके से सेट करने के लिए, बस के बजाय इसे फिर से उपयोग कर सकते हैं।

1

volatile कीवर्ड का उपयोग करने से पहले, आपको this पढ़ना चाहिए और, मुझे लगता है कि बहु-थ्रेडिंग का शोध करते समय आप पूरे http://www.albahari.com/threading/ आलेख को पढ़ सकते हैं।

यह volatile कीवर्ड की सूक्ष्मता बताता है और इसका व्यवहार अप्रत्याशित क्यों हो सकता है।


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


देखने के बाद, मैं अपने कोड कई कारणों से काम करता है नहीं लगता है,

"बूलियन:" टुकड़ा हमेशा नहीं लगभग एक पल के लिए सोता है, शायद तुम क्या चाहते।

"ऑटो रीसेट:" स्निपेट _stop को तुरंत चालू नहीं करता है, और हमेशा कम से कम एक बार doWork() चलाएगा।

+0

मैं _stop.WaitOne() पर ''! भूल गया था। ये उदाहरण थोड़ा सा सरल हैं, लेकिन मूल रूप से मैं समय-समय पर 'doWork() 'को चलाने के लिए चाहता हूं। 'DoWork()' तब तक चलेगा जब तक कि यह काम से बाहर नहीं हो जाता है, जिसके बाद इसे नए काम के लिए थोड़ी देर इंतजार करना पड़ता है। – Sjoerd

+0

@Sjoerd, मैंने अपना आखिरी हिस्सा संपादित किया।'अस्थिर' के आसपास सावधानी अभी भी प्रासंगिक है। – Jodrell

6

अस्थिरता पर्याप्त नहीं है, लेकिन व्यावहारिक रूप से यह हमेशा काम करेगा क्योंकि ऑपरेटिंग सिस्टम शेड्यूलर हमेशा अंततः लॉक लेगा। और एक मजबूत मेमोरी मॉडल के साथ कोर पर अच्छी तरह से काम करेगा, जैसे कि x86 जो कोर के बीच सिंक्रनाइज़ किए गए कैश को रखने के लिए बहुत सारे रस को जलता है।

तो वास्तव में केवल मायने रखता है कि थ्रेड स्टॉप अनुरोध को कितनी जल्दी प्रतिक्रिया देगा। मापना आसान है, बस नियंत्रण थ्रेड में स्टॉपवॉच शुरू करें और कार्यकर्ता थ्रेड में थोड़ी देर के बाद समय रिकॉर्ड करें। परिणाम मैं दोहरा 1000 नमूने ले रहे हैं और औसत लेने से मापा जाता है, बार-बार 10 गुना:

volatile bool, x86:   550 nanoseconds 
volatile bool, x64:   550 nanoseconds 
ManualResetEvent, x86:  2270 nanoseconds 
ManualResetEvent, x64:  2250 nanoseconds 
AutoResetEvent, x86:  2500 nanoseconds 
AutoResetEvent, x64:  2100 nanoseconds 
ManualResetEventSlim, x86: 650 nanoseconds 
ManualResetEventSlim, x64: 630 nanoseconds 

खबरदार कि अस्थिर bool के लिए परिणाम बहुत, एक कमजोर स्मृति मॉडल के साथ एक प्रोसेसर पर कि अच्छी तरह से देखने के लिए एआरएम तरह की संभावना नहीं है या Itanium। मेरे पास परीक्षण करने के लिए कोई नहीं है।

स्पष्ट रूप से ऐसा लगता है कि आप मैन्युअल रीसेट इवेंटस्लिम का पक्ष लेना चाहते हैं, अच्छे perf और गारंटी दे रहे हैं।

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

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