दिलचस्प पोस्ट
यह कैसे पता चलेगा कि आईओएस में पोर्ट्रेट ओरिएंटेशन, या लैंडस्केप में एक वीडियो फ़ाइल रिकॉर्ड की गई थी सी किसी भी मौजूदा सामग्री को अधिलेखित किए बिना एक बाइनरी फ़ाइल के बीच में लिखें Asp.net mvc 4 में स्वरूपित करें एंड्रॉइड वेबव्यू में फ़ॉन्ट साइज को कैसे बदल सकता है? सबसे आम एसक्यूएल विरोधी पैटर्न क्या हैं? बिना किसी अधिलेखन के रजिस्टर के पेस्ट कैसे करें क्लास में यह क्या अंतर है और यह जावा में है क्लिक करने योग्य / संपादन योग्य विजेट के साथ सूची दृश्य वस्तु को एक उपयोगी स्थिति में छोड़ने जा रहा है? एएसएक्स का प्रयोग करके जेएसओएन को PHP पर भेजा जा रहा है ड्रॉपडाउन चयन के आधार पर डेटाबेस से एक और चुनिंदा ड्रॉपडाउन जनरेट करें जावा में एक बूलियन पर एक बिटवे ऑपरेटर का प्रभाव Java प्रोजेक्ट में रिश्तेदार पथ से फ़ाइल कैसे पढ़ा जाए? java.io.File निर्दिष्ट पथ नहीं ढूँढ सकता पर्ल के प्रयोग से दो सरणी का अंतर सी और सी ++ में इंडेक्स द्वारा एरेज़ एक्सेस करना

सी # घटनाक्रम और थ्रेड सुरक्षा

मैं अक्सर निम्नलिखित सलाह सुना / पढ़ें:

हमेशा एक घटना की प्रतिलिपि बनाएं, इससे पहले कि आप इसे null करने के लिए जांचें और उसे आग लगा दें। यह थ्रेडिंग के साथ एक संभावित समस्या को समाप्त करेगा जहां ईवेंट स्थान पर null हो जाता है, जहां आप रिक्त स्थान की जांच करते हैं और जहां आप घटना को आग लगाते हैं:

 // Copy the event delegate before checking/calling EventHandler copy = TheEvent; if (copy != null) copy(this, EventArgs.Empty); // Call any handlers on the copied list 

अपडेट किया गया : मैंने ऑप्टिमाइज़ेशन के बारे में पढ़ने से सोचा था कि यह भी घटना के सदस्य को अस्थिर होने की आवश्यकता हो सकती है, लेकिन जॉन स्कीट ने अपने जवाब में कहा है कि CLR प्रतिलिपि का अनुकूलन नहीं करता है।

लेकिन इस बीच, इस मुद्दे को यहां तक ​​पहुंचने के क्रम में, एक और सूत्र ने ऐसा कुछ किया होगा:

 // Better delist from event - don't want our handler called from now on: otherObject.TheEvent -= OnTheEvent; // Good, now we can be certain that OnTheEvent will not run... 

वास्तविक अनुक्रम इस मिश्रण हो सकता है:

 // Copy the event delegate before checking/calling EventHandler copy = TheEvent; // Better delist from event - don't want our handler called from now on: otherObject.TheEvent -= OnTheEvent; // Good, now we can be certain that OnTheEvent will not run... if (copy != null) copy(this, EventArgs.Empty); // Call any handlers on the copied list 

यह मुद्दा यह है कि लेखक ने सदस्यता समाप्त होने के बाद OnTheEvent चलाता है, और फिर भी वे विशेष रूप से उस होने से बचने के लिए सदस्यता समाप्त कर देते हैं। निश्चित रूप से वास्तव में क्या जरूरत है एक कस्टम ईवेंट क्रियान्वयन है जिसमें एक्सेसर्स को add और remove में उपयुक्त सिंक्रनाइज़ेशन है। और इसके अलावा संभावित डेडलॉक की समस्या है, अगर कोई इवेंट उड़ाया जाता है तो लॉक आयोजित किया जाता है।

तो क्या यह कार्गो कल्ट प्रोग्रामिंग है ? ऐसा लगता है कि – बहुत से लोगों को अपने कोड को कई सूत्रों से सुरक्षित रखने के लिए यह कदम उठाना चाहिए, जब वास्तविकता में मुझे लगता है कि घटनाओं को इससे अधिक ध्यान देने की आवश्यकता होती है इससे पहले कि वे बहु-पिरोया डिजाइन के भाग के रूप में इस्तेमाल किए जा सकें । नतीजतन, जो लोग अतिरिक्त देखभाल नहीं ले रहे हैं वे इस सलाह को अनदेखा भी कर सकते हैं – यह केवल एकल-थ्रेडेड कार्यक्रमों के लिए कोई मुद्दा नहीं है, और वास्तव में, अधिकांश ऑनलाइन उदाहरण कोड में volatile की अनुपस्थिति को देखते हुए, सलाह हो सकती है बिल्कुल भी कोई प्रभाव नहीं।

(और सदस्य घोषणा पर रिक्त delegate { } निर्दिष्ट करने के लिए यह बहुत आसान नहीं है ताकि आपको पहली जगह में null जांच करने की ज़रूरत न पड़े?)

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

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

एरिक लिपर्ट के ब्लॉग पोस्ट के जवाब में अद्यतन:

इसलिए घटना प्रबंधनकर्ताओं के बारे में मुझे एक बड़ी चीज है: "घटना को रद्द करने के बाद भी बुलाए जाने के चेहरे पर इवेंट हैंन्डलर को मजबूत करना आवश्यक है", और जाहिर तौर पर इसलिए हमें घटना की संभावना के बारे में केवल ध्यान रखना होगा प्रतिनिधि null होने के नाते क्या ईवेंट हैंडलर्स पर यह आवश्यकता कहीं भी दर्ज़ है?

और इसलिए: "इस समस्या को सुलझाने के अन्य तरीके हैं, उदाहरण के लिए, हैंडलर को एक खाली क्रिया करने के लिए आरंभ करने के लिए प्रारंभ नहीं किया जाता है, लेकिन एक निरर्थक जांच करना मानक स्वरूप है।"

तो मेरे सवाल का शेष टुकड़ा है, "मानक पैटर्न" स्पष्ट-रिक्त-जांच क्यों है? वैकल्पिक, रिक्त प्रतिनिधि को निर्दिष्ट करने के लिए, केवल घटना के घोषणा में जोड़ा जाने के लिए केवल = delegate {} आवश्यकता होती है, और यह उन जगहों के उन छोटे बवासीरों को समाप्त करता है जहां घटना उठाया जाता है। यह सुनिश्चित करना आसान होगा कि रिक्त प्रतिनिधि इन्स्तांत करने के लिए सस्ता है। या मैं अभी भी कुछ याद कर रहा हूँ?

निश्चित रूप से यह होना चाहिए (जैसा कि जॉन स्कीट ने सुझाव दिया है) यह सिर्फ .नेट 1.x की सलाह है जो कि मर नहीं गया है, क्योंकि यह 2005 में किया जाना चाहिए था?

Solutions Collecting From Web of "सी # घटनाक्रम और थ्रेड सुरक्षा"

स्थिति के कारण, जेआईटी को पहले भाग में आप के बारे में बात कर रहे अनुकूलन करने की अनुमति नहीं है। मुझे पता है कि यह कुछ समय पहले एक भूत के रूप में उठाया गया था, लेकिन यह मान्य नहीं है। (मैंने इसे कुछ समय पहले जो डफी या वेंस मॉरिसन के साथ किया था, मुझे याद नहीं है जो।)

वाष्पशील संशोधक के बिना यह संभव है कि प्रतिलिपि की स्थानीय प्रतिदीप्ति पुरानी हो जाएगी, लेकिन यह सब कुछ है। यह एक NullReferenceException कारण नहीं होगा

और हाँ, निश्चित रूप से एक दौड़ की स्थिति है – लेकिन हमेशा वहाँ होगा। मान लीजिए हम सिर्फ कोड को बदलते हैं:

 TheEvent(this, EventArgs.Empty); 

अब मान लीजिए कि उस प्रतिनिधि के लिए अभिविन्यास सूची में 1000 प्रविष्टियां हैं यह पूरी तरह से संभव है कि सूची के अंत के निकट एक हैंडलर का त्यागने से पहले सूची की शुरुआत में क्रिया को निष्पादित किया जाएगा। हालांकि, वह हैंडलर अभी भी निष्पादित होगा क्योंकि यह एक नई सूची होगी (प्रतिनिधियों अपरिवर्तनीय हैं।) जहां तक ​​मैं देख सकता हूं यह अपरिहार्य है।

रिक्त प्रतिनिधि का उपयोग निश्चित रूप से निरंतरता की जांच से बचा जाता है, लेकिन रेस की स्थिति को ठीक नहीं करता है यह भी गारंटी नहीं देता है कि आप हमेशा चर के नवीनतम मान "देखें"

मैं बहुत सारे लोगों को यह करने की विस्तार विधि की ओर देख रहा हूं …

 public static class Extensions { public static void Raise<T>(this EventHandler<T> handler, object sender, T args) where T : EventArgs { if (handler != null) handler(sender, args); } } 

यह आपको घटना को बढ़ाने के लिए अच्छे सिंटैक्स देता है …

 MyEvent.Raise( this, new MyEventArgs() ); 

और स्थानीय प्रतिलिपि के साथ भी दूर करता है क्योंकि यह विधि कॉल समय पर कब्जा कर लिया गया है।

"क्यों 'मानक पैटर्न' स्पष्ट-रिक्त-जांच करें? ''

मुझे इस बात का संदेह है कि यह हो सकता है कि निरर्थक जांच अधिक प्रदर्शनकारी है

यदि आप हमेशा अपने इवेंट में एक खाली प्रतिनिधि को सब्सक्राइब करते हैं, तो कुछ ओवरहेड्स होंगे:

  • खाली प्रतिनिधि का निर्माण करने की लागत
  • इसे शामिल करने के लिए एक प्रतिनिधि श्रृंखला का निर्माण करने की लागत
  • व्यर्थ प्रतिनिधि को हर बार इस घटना को उठाया जाता है।

(ध्यान दें कि यूआई के नियंत्रण में अक्सर बड़ी संख्या में घटनाएं होती हैं, जिनमें से अधिकांश को कभी भी सदस्यता नहीं मिलती है। प्रत्येक घटना के लिए एक डमी ग्राहक बनाने के बाद और फिर यह एक महत्वपूर्ण प्रदर्शन हिट होगा।

मैंने सदस्यता-रिक्त-प्रतिनिधि दृष्टिकोण के प्रभाव को देखने के लिए कुछ सरसरी प्रदर्शन परीक्षण किए, और यहां मेरे परिणाम हैं:

 Executing 50000000 iterations . . . OnNonThreadSafeEvent took: 432ms OnClassicNullCheckedEvent took: 490ms OnPreInitializedEvent took: 614ms <-- Subscribing an empty delegate to each event . . . Executing 50000000 iterations . . . OnNonThreadSafeEvent took: 674ms OnClassicNullCheckedEvent took: 674ms OnPreInitializedEvent took: 2041ms <-- Subscribing another empty delegate to each event . . . Executing 50000000 iterations . . . OnNonThreadSafeEvent took: 2011ms OnClassicNullCheckedEvent took: 2061ms OnPreInitializedEvent took: 2246ms <-- Done 

ध्यान दें कि शून्य या एक ग्राहक के मामले (यूआई कंट्रोल्स के लिए सामान्य है, जहां घटनाएं भरपूर हैं), एक खाली प्रतिनिधि के साथ पूर्व में शुरू होने वाला कार्यक्रम उल्लेखनीय रूप से धीमा है (50 मिलियन से अधिक पुनरावृत्तियों …)

अधिक जानकारी और स्रोत कोड के लिए, इस ब्लॉग पोस्ट पर जाइए। एनईटी इवेंट इनवॉइस धागा सुरक्षा जो मैंने इस प्रश्न के पहले ही प्रकाशित किया था (!)

(मेरा परीक्षण सेट अप गलत हो सकता है, इसलिए सोर्स कोड को डाउनलोड करने और इसे अपने आप का निरीक्षण करने में संकोच न करें। कोई भी प्रतिक्रिया बहुत सराहना की जाती है।)

मैं वास्तव में इस पढ़ने का आनंद लिया – नहीं! भले ही मुझे इसे सी # फीचर नामक घटनाओं के साथ काम करने की ज़रूरत है!

क्यों संकलक में इसे ठीक नहीं? मुझे पता है कि एमएस लोग हैं जो इन पदों को पढ़ते हैं, तो कृपया इस बात की ज्योति मत करो!

1 – नल जारी ) क्यों नहीं घटनाएं बनें। पहली जगह में रिक्त स्थान की बजाय? रिक्त जांच के लिए कोड की कितनी लाइनें सहेजी जाएंगी या घोषित करने के लिए = delegate {} को छोडना होगा? कंपाइलर को रिक्त मामले को संभालने दें, IE कुछ भी नहीं करता है! यदि यह सभी घटना के निर्माता के लिए मायने रखता है, तो वे जांच कर सकते हैं। कुछ भी करो और जो कुछ भी उनकी देखभाल करते हैं! अन्यथा सभी रिक्त चेक / प्रतिनिधि जोड़ समस्या के आसपास हैक्स हैं!

ईमानदारी से मैं हर घटना के साथ ऐसा करने के थक गया हूँ – उर्फ ​​बॉयलरप्लेट कोड!

 public event Action<thisClass, string> Some; protected virtual void DoSomeEvent(string someValue) { var e = Some; // avoid race condition here! if(null != e) // avoid null condition here! e(this, someValue); } 

2 – दौड़ की स्थिति की समस्या ) मैंने एरिक के ब्लॉग पोस्ट को पढ़ा है, मैं मानता हूं कि एच (हैंडलर) को अपने आप को डीरेफेंस करना चाहिए, लेकिन क्या घटना को अस्थायी / धागा सुरक्षित नहीं बनाया जा सकता है? IE, इसके सृजन पर एक लॉक फ्लैग सेट किया गया है, ताकि जब भी इसे कहा जाए, तो यह सब निष्पादन करने और उसके निष्पादन के दौरान इसकी सदस्यता रद्द करने के लिए लॉक करता है?

निष्कर्ष ,

क्या आज की आधुनिक भाषाओं में ये समस्याएं हल नहीं होती हैं?

सीएलआर के माध्यम से सी # में जेफरी रिचटर के अनुसार, सही विधि है:

 // Copy a reference to the delegate field now into a temporary field for thread safety EventHandler<EventArgs> temp = Interlocked.CompareExchange(ref NewMail, null, null); // If any methods registered interest with our event, notify them if (temp != null) temp(this, e); 

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

मैं यह डिज़ाइन पैटर्न का उपयोग कर रहा हूं ताकि यह सुनिश्चित हो सके कि ईवेंट हैंडलर्स को सदस्यता समाप्त होने के बाद निष्पादित नहीं किया गया है। यह अभी तक बहुत अच्छी तरह से काम कर रहा है, हालांकि मैंने किसी भी प्रदर्शन प्रोफाइलिंग की कोशिश नहीं की है

 private readonly object eventMutex = new object(); private event EventHandler _onEvent = null; public event EventHandler OnEvent { add { lock(eventMutex) { _onEvent += value; } } remove { lock(eventMutex) { _onEvent -= value; } } } private void HandleEvent(EventArgs args) { lock(eventMutex) { if (_onEvent != null) _onEvent(args); } } 

मैं ज्यादातर इन दिनों एंड्रॉ के लिए मोनो के साथ काम कर रहा हूं, और एंड्रॉइड इसे पसंद करने के लिए ऐसा नहीं लगता है जब आप एक ऐप अपडेट करने की कोशिश करते हैं, इसकी गतिविधि को पृष्ठभूमि में भेज दिया गया है।

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

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

नोट: दौड़ की स्थिति तय करने में शायद एक तुल्यकालिक ध्वज ट्रैक का उपयोग करना शामिल है कि क्या हैंडलर चलाना चाहिए

इसलिए मैं यहां पार्टी के लिए थोड़ा देर कर रहा हूं। 🙂

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

इस बात को ध्यान में रखते हुए, एक समाधान यह है कि "ठीक है, शून्य ग्राहकों का प्रतिनिधित्व शून्य है।" फिर अपने महंगी ऑपरेशन को करने से पहले केवल रिक्त जांच करें। मुझे लगता है कि ऐसा करने का एक अन्य तरीका प्रतिनिधि के प्रकार पर एक गिनती की संपत्ति होगी, इसलिए यदि आप केवल myDelegate.Count> 0. महंगी ऑपरेशन करते हैं, तो गणना गुण 0. मूल गुण की समस्या का समाधान करने वाला कुछ अच्छा पैटर्न है ऑप्टिमाइज़ेशन की अनुमति देने के लिए, और इसके पास एक NullReferenceException के कारण बिना लागू होने की अच्छी संपत्ति भी है

ध्यान रखें, हालांकि, जब प्रतिनिधियों के संदर्भ प्रकार होते हैं, तो वे निरर्थक होने की अनुमति देते हैं। संभवतः कवर के तहत इस तथ्य को छिपाने का कोई अच्छा तरीका नहीं था और घटनाओं के लिए केवल रिक्त ऑब्जेक्ट पैटर्न का समर्थन किया गया था, इसलिए वैकल्पिक डेवलपर्स को रिक्त और शून्य ग्राहकों के लिए दोनों की जांच करने के लिए मजबूर किया गया हो सकता है। यह मौजूदा स्थिति की तुलना में भी बेकार होगा।

नोट: यह शुद्ध अटकलें हैं मैं .NET भाषाओं या CLR के साथ शामिल नहीं हूं।

एकल थ्रेडेड आवेदनाओं के लिए, आप correc हैं यह कोई समस्या नहीं है।

हालांकि, यदि आप एक घटक बना रहे हैं जो घटनाओं को उजागर करता है, तो इसमें कोई गारंटी नहीं है कि आपके घटक के एक उपभोक्ता multithreading नहीं जा रहे हैं, इस स्थिति में आपको सबसे बुरी तरह से तैयार करने की आवश्यकता है

रिक्त प्रतिनिधि का उपयोग समस्या का समाधान करता है, लेकिन ईवेंट के प्रत्येक कॉल पर एक प्रदर्शन को भी प्रभावित करता है, और संभवत: जीसी प्रभाव हो सकता है

आप सही हैं कि उपभोक्ता trie dto इस के लिए आदेश में सदस्यता समाप्त, लेकिन अगर वे इसे अस्थायी प्रति पिछले अतीत, तो पहले से ही पारगमन में संदेश पर विचार करें

यदि आप अस्थायी चर का उपयोग नहीं करते हैं, और रिक्त प्रतिनिधि का उपयोग नहीं करते हैं, और कोई व्यक्ति सदस्यता समाप्त करता है, तो आपको एक अशक्त संदर्भ अपवाद मिलता है, जो घातक है, इसलिए मुझे लगता है कि लागत इसके लायक है।

मैंने वास्तव में इस मुद्दे पर ज्यादा विचार नहीं किया है क्योंकि मैं आम तौर पर केवल अपने पुन: उपयोग करने योग्य घटकों पर स्थिर तरीकों (आदि) में इस तरह के संभावित थ्रेडिंग बुराई से रक्षा करता हूं, और मैं स्थिर घटनाओं को नहीं बनाता

क्या मैं यह गलत कर रहा हूं?

निर्माण पर अपने सभी ईवेंट तार करें और उन्हें अकेले छोड़ दें प्रतिनिधि वर्ग का डिज़ाइन संभवतः किसी भी अन्य उपयोग को सही ढंग से नियंत्रित नहीं कर सकता है, क्योंकि मैं इस पोस्ट के अंतिम अनुच्छेद में समझाऊंगा।

सबसे पहले, कोई इवेंट नोटिफिकेशन को रोकने की कोशिश करने का कोई मतलब नहीं है, जब आपके ईवेंट हैंडलर पहले से ही सिंक्रनाइज़ किए गए निर्णय के बारे में पहले से ही कर रहे हैं कि क्या सूचना / सूचना का जवाब देना है

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

केवल एक बार एक हैंडलर को सूचित नहीं किया जाना चाहिए कि कोई घटना हुई है, यह है कि वास्तव में घटना नहीं हुई है! इसलिए यदि आप एक हैंडलर को अधिसूचित नहीं करना चाहते हैं, तो घटनाओं को सृजित करना बंद करें (यानी नियंत्रण को अक्षम करें या पहले स्थान पर घटना को अस्तित्व में लाने और लाने के लिए जिम्मेदार है)।

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

Please take a look here: http://www.danielfortunov.com/software/%24daniel_fortunovs_adventures_in_software_development/2009/04/23/net_event_invocation_thread_safety This is the correct solution and should always be used instead of all other workarounds.

“You can ensure that the internal invocation list always has at least one member by initializing it with a do-nothing anonymous method. Because no external party can have a reference to the anonymous method, no external party can remove the method, so the delegate will never be null” — Programming .NET Components, 2nd Edition, by Juval Löwy

 public static event EventHandler<EventArgs> PreInitializedEvent = delegate { }; public static void OnPreInitializedEvent(EventArgs e) { // No check required - event will never be null because // we have subscribed an empty anonymous delegate which // can never be unsubscribed. (But causes some overhead.) PreInitializedEvent(null, e); } 

I don't believe the question is constrained to the c# "event" type. Removing that restriction, why not re-invent the wheel a bit and do something along these lines?

Raise event thread safely – best practice

  • Ability to sub/unsubscribe from any thread while within a raise (race condition removed)
  • Operator overloads for += and -= at the class level.
  • Generic caller-defined delegate

Thanks for a useful discussion. I was working on this problem recently and made the following class which is a bit slower, but allows to avoid callings to disposed objects.

The main point here is that invocation list can be modified even event is raised.

 /// <summary> /// Thread safe event invoker /// </summary> public sealed class ThreadSafeEventInvoker { /// <summary> /// Dictionary of delegates /// </summary> readonly ConcurrentDictionary<Delegate, DelegateHolder> delegates = new ConcurrentDictionary<Delegate, DelegateHolder>(); /// <summary> /// List of delegates to be called, we need it because it is relatevely easy to implement a loop with list /// modification inside of it /// </summary> readonly LinkedList<DelegateHolder> delegatesList = new LinkedList<DelegateHolder>(); /// <summary> /// locker for delegates list /// </summary> private readonly ReaderWriterLockSlim listLocker = new ReaderWriterLockSlim(); /// <summary> /// Add delegate to list /// </summary> /// <param name="value"></param> public void Add(Delegate value) { var holder = new DelegateHolder(value); if (!delegates.TryAdd(value, holder)) return; listLocker.EnterWriteLock(); delegatesList.AddLast(holder); listLocker.ExitWriteLock(); } /// <summary> /// Remove delegate from list /// </summary> /// <param name="value"></param> public void Remove(Delegate value) { DelegateHolder holder; if (!delegates.TryRemove(value, out holder)) return; Monitor.Enter(holder); holder.IsDeleted = true; Monitor.Exit(holder); } /// <summary> /// Raise an event /// </summary> /// <param name="args"></param> public void Raise(params object[] args) { DelegateHolder holder = null; try { // get root element listLocker.EnterReadLock(); var cursor = delegatesList.First; listLocker.ExitReadLock(); while (cursor != null) { // get its value and a next node listLocker.EnterReadLock(); holder = cursor.Value; var next = cursor.Next; listLocker.ExitReadLock(); // lock holder and invoke if it is not removed Monitor.Enter(holder); if (!holder.IsDeleted) holder.Action.DynamicInvoke(args); else if (!holder.IsDeletedFromList) { listLocker.EnterWriteLock(); delegatesList.Remove(cursor); holder.IsDeletedFromList = true; listLocker.ExitWriteLock(); } Monitor.Exit(holder); cursor = next; } } catch { // clean up if (listLocker.IsReadLockHeld) listLocker.ExitReadLock(); if (listLocker.IsWriteLockHeld) listLocker.ExitWriteLock(); if (holder != null && Monitor.IsEntered(holder)) Monitor.Exit(holder); throw; } } /// <summary> /// helper class /// </summary> class DelegateHolder { /// <summary> /// delegate to call /// </summary> public Delegate Action { get; private set; } /// <summary> /// flag shows if this delegate removed from list of calls /// </summary> public bool IsDeleted { get; set; } /// <summary> /// flag shows if this instance was removed from all lists /// </summary> public bool IsDeletedFromList { get; set; } /// <summary> /// Constuctor /// </summary> /// <param name="d"></param> public DelegateHolder(Delegate d) { Action = d; } } } 

And the usage is:

  private readonly ThreadSafeEventInvoker someEventWrapper = new ThreadSafeEventInvoker(); public event Action SomeEvent { add { someEventWrapper.Add(value); } remove { someEventWrapper.Remove(value); } } public void RaiseSomeEvent() { someEventWrapper.Raise(); } 

Test

I tested it in the following manner. I have a thread which creates and destroys objects like this:

 var objects = Enumerable.Range(0, 1000).Select(x => new Bar(foo)).ToList(); Thread.Sleep(10); objects.ForEach(x => x.Dispose()); 

In a Bar (a listener object) constructor I subscribe to SomeEvent (which is implemented as shown above) and unsubscribe in Dispose :

  public Bar(Foo foo) { this.foo = foo; foo.SomeEvent += Handler; } public void Handler() { if (disposed) Console.WriteLine("Handler is called after object was disposed!"); } public void Dispose() { foo.SomeEvent -= Handler; disposed = true; } 

Also I have couple of threads which raise event in a loop.

All these actions are performed simultaneously: many listeners are created and destroyed and event is being fired at the same time.

If there were a race conditions I should see a message in a console, but it is empty. But if I use clr events as usual I see it full of warning messages. So, I can conclude that it is possible to implement a thread safe events in c#.

तुम क्या सोचते हो?

With C# 6 and above, code could be simplified using new .? operator as in TheEvent?.Invoke(this, EventArgs.Empty);

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators