C # में विभिन्न सूत्रण सिंक्रनाइज़ेशन विकल्पों के बीच अंतर क्या हैं?


164

क्या कोई इसके बीच का अंतर समझा सकता है:

  • ताला (कोई बात) {}
  • म्यूटेक्स का उपयोग करना
  • सेमाफोर का उपयोग करना
  • मॉनिटर का उपयोग करना
  • अन्य .Net तुल्यकालन वर्गों का उपयोग करना

मैं अभी इसका पता नहीं लगा सकता। ऐसा लगता है कि पहले दो समान हैं?


इस लिंक से मुझे बहुत मदद मिली: अल्बाहारी। इनथ्रेडिंग
राफेल

जवाबों:


135

बड़ा सवाल है। मैं शायद गलत हूं .. मुझे कोशिश करें .. मेरे मूल उत्तर का # संशोधन 2 .. थोड़ा और अधिक समझ के साथ। मुझे पढ़ने के लिए धन्यवाद :)

ताला (obj)

  • एक सीएलआर निर्माण (इंट्रा-ऑब्जेक्ट?) थ्रेड सिंक्रोनाइज़ेशन है। सुनिश्चित करता है कि केवल एक धागा ऑब्जेक्ट के लॉक का स्वामित्व ले सकता है और कोड के लॉक किए गए ब्लॉक में प्रवेश कर सकता है। अन्य धागे को तब तक इंतजार करना चाहिए जब तक कि वर्तमान मालिक कोड के ब्लॉक से बाहर निकलकर ताला को त्याग नहीं देता। इसके अलावा, यह अनुशंसा की जाती है कि आप अपनी कक्षा के किसी निजी सदस्य ऑब्जेक्ट पर लॉक करें।

पर नज़र रखता है

  • लॉक (obj) आंतरिक रूप से मॉनिटर का उपयोग करके कार्यान्वित किया जाता है। आपको लॉक (ओब्ज) पसंद करना चाहिए क्योंकि यह आपको सफाई प्रक्रिया को भूलने की तरह जाने से रोकता है। यदि आप करेंगे तो यह बेवकूफ-प्रूफ का मॉनीटर निर्माण है।
    मॉनिटर का उपयोग करना आमतौर पर म्यूटेक्स पर पसंद किया जाता है, क्योंकि मॉनिटर विशेष रूप से .NET फ्रेमवर्क के लिए डिज़ाइन किए गए थे और इसलिए संसाधनों का बेहतर उपयोग करते हैं।

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

म्युटेक्स:

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

सेमाफोरस (मेरे मस्तिष्क को चोट)।

  • संसाधनों के एक पूल तक पहुंच को नियंत्रित करने के लिए सेमाफोर वर्ग का उपयोग करें। थ्रेड्स WaitOne विधि को कॉल करके सेमाफोर में प्रवेश करते हैं, जो कि WaitHandle वर्ग से विरासत में मिला है, और रिलीज़ विधि को कॉल करके सेमाफ़ोर जारी करते हैं। एक सेमाफोर पर गिनती हर बार घट जाती है जब एक धागा सेमीफोर में प्रवेश करता है, और एक थ्रेड सेमाफोर रिलीज होने पर बढ़ जाता है। जब गिनती शून्य होती है, तो बाद के अनुरोध तब तक अवरुद्ध करते हैं जब तक कि अन्य धागे सेमाफोर जारी नहीं करते। जब सभी थ्रेड्स ने सेमाफोर जारी किया है, तो गिनती को अधिकतम मूल्य पर निर्दिष्ट किया गया है जब सेमाफोर बनाया गया था। एक धागा कई बार सेमाफोर में प्रवेश कर सकता है..समाफोर वर्ग वेटऑन या रिलीज पर थ्रेड आइडेंटिफिकेशन लागू नहीं करता है .. प्रोग्रामर जिम्मेदारी नहीं समझते। सेमाफोर दो प्रकार के होते हैं: स्थानीय सेमाफोर और नामितसिस्टम सेमाफोर्स। यदि आप एक निर्माता का उपयोग करके एक सेमाफोर ऑब्जेक्ट बनाते हैं जो किसी नाम को स्वीकार करता है, तो यह उस नाम के ऑपरेटिंग-सिस्टम सेमाफोर से जुड़ा होता है। पूरे सिस्टम में नामांकित सिस्टम सेमाफोर दिखाई देते हैं, और इसका उपयोग प्रक्रियाओं की गतिविधियों को सिंक्रनाइज़ करने के लिए किया जा सकता है। एक स्थानीय सेमाफोर आपकी प्रक्रिया के भीतर ही मौजूद है। यह आपकी प्रक्रिया में किसी भी थ्रेड द्वारा उपयोग किया जा सकता है जिसमें स्थानीय सेमाफोर ऑब्जेक्ट का संदर्भ होता है। प्रत्येक सेमाफोर ऑब्जेक्ट एक अलग स्थानीय सेमाफोर है।

पढ़ें पेज - थ्रेड सिंक्रोनाइज़ेशन (C #)


18
आप दावा करते हैं कि Monitorसंचार की अनुमति नहीं देना गलत है; आप कर सकते हैं अभी भी Pulseआदि एक साथMonitor
मार्क Gravell

3
Semaphores का एक वैकल्पिक विवरण देखें - stackoverflow.com/a/40473/968003 । एक नाइट क्लब में बाउंसर के रूप में सेमाफोरस के बारे में सोचो। एक बार में क्लब में अनुमति देने वाले लोगों की एक समर्पित संख्या होती है। यदि क्लब भरा हुआ है तो किसी को भी प्रवेश करने की अनुमति नहीं है, लेकिन जैसे ही एक व्यक्ति दूसरे व्यक्ति को छोड़ता है, वह प्रवेश कर सकता है।
एलेक्स क्लॉज़

31

"अन्य .Net तुल्यकालन वर्गों का उपयोग करना" - कुछ अन्य जिनके बारे में आपको पता होना चाहिए:

  • ReaderWriterLock - कई पाठकों या एक ही लेखक को अनुमति देता है (एक ही समय में नहीं)
  • ReaderWriterLockSlim - ऊपर की तरह, निचला ओवरहेड
  • ManualResetEvent - एक गेट जो खुले होने पर कोड अतीत की अनुमति देता है
  • AutoResetEvent - जैसा कि ऊपर है, लेकिन एक बार खुलने के बाद स्वचालित रूप से बंद हो जाता है

CCR / TPL ( समानांतर एक्सटेंशन CTP) में अधिक (कम ओवरहेड) लॉकिंग निर्माण भी हैं - लेकिन IIRC, इन्हें .NET 4.0 में उपलब्ध कराया जाएगा।


तो अगर मैं एक साधारण संकेत संचार (एक async सेशन के पूरा होने पर कहना चाहता हूँ) - मैं Monitor.Pulse चाहिए? या SemaphoreSlim या TaskCompletionSource का उपयोग करें?
विवेक

Async ऑपरेशन के लिए TaskCompletionSource का उपयोग करें। मूल रूप से, थ्रेड्स के बारे में सोचना बंद करें और कार्यों (काम की इकाइयों) के बारे में सोचना शुरू करें। थ्रेड्स कार्यान्वयन विवरण हैं और प्रासंगिक नहीं हैं। एक TCS वापस करके, आप परिणाम, त्रुटियां या रद्दीकरण को वापस कर सकते हैं और यह आसानी से अन्य async ऑपरेशन (जैसे async प्रतीक्षा या ContinueWith) के साथ आसानी से लिखने योग्य है।
साइमन गिल्बी

14

जैसा कि ईसीएमए में कहा गया है, और जैसा कि आप प्रतिबिंबित तरीकों से देख सकते हैं कि लॉक स्टेटमेंट मूल रूप से इसके बराबर है

object obj = x;
System.Threading.Monitor.Enter(obj);
try {
   
}
finally {
   System.Threading.Monitor.Exit(obj);
}

उपरोक्त उदाहरण से हम देखते हैं कि मॉनिटर्स वस्तुओं पर ताला लगा सकते हैं।

जब आप एक स्ट्रिंग पहचानकर्ता पर ताला लगा सकते हैं, तो आपको म्यूटेक्स के इंटरप्रोसेस सिंक्रनाइज़ेशन की आवश्यकता होती है । लॉक को प्राप्त करने के लिए एक ही स्ट्रिंग पहचानकर्ता का उपयोग विभिन्न प्रक्रियाओं द्वारा किया जा सकता है।

सेराफोर स्टेरॉयड पर म्यूटेक्स की तरह हैं, वे समवर्ती पहुंच की अधिकतम गिनती प्रदान करके समवर्ती पहुंच की अनुमति देते हैं '। एक बार जब सीमा समाप्त हो जाती है तो सेमीफोर रिसोर्स तक किसी और एक्सेस को ब्लॉक करना शुरू कर देता है जब तक कि कॉलर का एक सेमाफोर रिलीज नहीं होता।


5
इस सिंथैटिक शुगर को C # 4 में थोड़ा बदल दिया गया है। blogs.msdn.com/ericlippert/archive/2009/03/06/… पर देखें
पीटर Gfader

14

मैंने DotGNU में थ्रेडिंग के लिए क्लासेस और CLR सपोर्ट किया और मेरे कुछ विचार हैं ...

जब तक आपको क्रॉस प्रक्रिया ताले की आवश्यकता नहीं होती है तब तक आपको म्यूटेक्स और सेमाफोरेस का उपयोग करने से हमेशा बचना चाहिए। .NET में ये कक्षाएं Win32 Mutex और Semaphores के आसपास रैपर हैं और बल्कि भारी हैं (उन्हें कर्नेल में एक संदर्भ स्विच की आवश्यकता होती है जो महंगा है - खासकर यदि आपका लॉक विवाद के अधीन नहीं है)।

जैसा कि अन्य लोगों ने उल्लेख किया है, C # लॉक स्टेटमेंट मॉनिटर.इंटर और मॉनिटर के लिए कंपाइलर मैजिक है। एक्ज़िट (कोशिश या अंत में मौजूद)।

मॉनिटर्स में एक सरल लेकिन शक्तिशाली सिग्नल / प्रतीक्षा तंत्र होता है, जो म्यूटेक्स के पास मॉनीटर नहीं है। Win32 समतुल्य ईवेंट ऑब्जेक्ट CreateEvent के माध्यम से होगा जो वास्तव में .NET में WaitHandles के रूप में भी मौजूद है। पल्स / वेट मॉडल, यूनिक्स के pthread_signal और pthread_wait के समान है, लेकिन तेज़ हैं क्योंकि वे पूरी तरह से अन-कंटेस्टेड केस में यूजर-मोड ऑपरेशन हो सकते हैं।

Monitor.Pulse / Wait का उपयोग करना सरल है। एक थ्रेड में, हम एक ऑब्जेक्ट को लॉक करते हैं, एक ध्वज / राज्य / संपत्ति की जांच करते हैं और अगर यह वह नहीं है जो हम उम्मीद कर रहे हैं, तो मॉनिटर को कॉल करें। जो लॉक को रिलीज़ करेगा और एक पल्स भेजे जाने तक प्रतीक्षा करेगा। जब प्रतीक्षा वापस आती है, तो हम वापस लूप करते हैं और ध्वज / राज्य / संपत्ति को फिर से जांचते हैं। दूसरे धागे में, जब भी हम झंडा / राज्य / संपत्ति बदलते हैं, तब हम ऑब्जेक्ट को लॉक करते हैं और फिर किसी भी सुनने वाले धागे को जगाने के लिए PulseAll को कॉल करते हैं।

अक्सर हम चाहते हैं कि हमारी कक्षाएं सुरक्षित रहें, इसलिए हम अपने कोड में ताले लगाते हैं। हालांकि, यह अक्सर ऐसा होता है कि हमारी कक्षा केवल एक धागे द्वारा कभी भी उपयोग की जाएगी। इसका मतलब यह है कि ताले अनावश्यक रूप से हमारे कोड को धीमा कर देते हैं ... यह वह जगह है जहां सीएलआर में चतुर अनुकूलन प्रदर्शन को बेहतर बनाने में मदद कर सकता है।

मुझे Microsoft के ताले के कार्यान्वयन के बारे में निश्चित नहीं है, लेकिन DotGNU और मोनो में, हर वस्तु के हेडर में एक लॉक स्टेट फ्लैग संग्रहीत है। .NET (और जावा) की प्रत्येक वस्तु एक ताला बन सकती है, इसलिए प्रत्येक वस्तु को अपने हेडर में इसका समर्थन करने की आवश्यकता होती है। DotGNU कार्यान्वयन में, एक झंडा होता है जो आपको हर वस्तु के लिए एक वैश्विक हैशटेबल का उपयोग करने की अनुमति देता है जिसे लॉक के रूप में उपयोग किया जाता है - इससे हर वस्तु के लिए 4 बाइट ओवरहेड को खत्म करने का लाभ होता है। यह मेमोरी के लिए महान नहीं है (विशेष रूप से एम्बेडेड सिस्टम के लिए जो भारी रूप से थ्रेडेड नहीं हैं) लेकिन प्रदर्शन पर हिट है।

मोनो और DotGNU दोनों प्रभावी रूप से लॉकिंग / वेटिंग करने के लिए म्यूटेक्स का उपयोग करते हैं, लेकिन वास्तव में आवश्यक होने तक हार्ड लॉक करने की आवश्यकता को समाप्त करने के लिए एक स्पिनलॉक शैली की तुलना और एक्सचेंज संचालन का उपयोग करते हैं:

आप इसका एक उदाहरण देख सकते हैं कि कैसे मॉनिटर को यहां लागू किया जा सकता है:

http://cvs.savannah.gnu.org/viewvc/dotgnu-pnet/pnet/engine/lib_monitor.c?revision=1.7&view=markup


9

एक स्ट्रिंग आईडी के साथ पहचाने गए किसी भी साझा म्यूटेक्स पर ताला लगाने के लिए एक अतिरिक्त चेतावनी यह है कि यह एक "स्थानीय \" म्यूटेक्स के लिए डिफ़ॉल्ट होगा और टर्मिनल सर्वर वातावरण में सत्र भर में साझा नहीं किया जाएगा।

"ग्लोबल \" के साथ अपने स्ट्रिंग आइडेंटिफ़ायर को सुनिश्चित करें कि साझा सिस्टम संसाधनों तक पहुंच ठीक से नियंत्रित हो। इससे पहले कि मुझे यह एहसास होता कि मैं सिस्टम खाते के तहत चल रही एक सेवा के साथ संचार को सिंक्रनाइज़ करने में समस्याओं का एक पूरा ढेर में चल रहा था।


5

मैं "ताला ()", "म्यूटेक्स" और "मॉनिटर" से बचने की कोशिश करूंगा यदि आप कर सकते हैं ...

नए नामस्थान सिस्टम की जाँच करें। पॉलिसियन। .NET 4 में समवर्ती।
इसमें कुछ अच्छे थ्रेड-सुरक्षित संग्रह वर्ग हैं।

http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx

समवर्ती चट्टानों! अब मेरे लिए कोई मैनुअल लॉकिंग नहीं है!


2
लॉक से बचें लेकिन मॉनिटर का उपयोग करें? क्यों?
मफू

@mafutrct क्योंकि आपको अपने आप को सिंक्रोनाइज़ेशन की देखभाल करने की आवश्यकता है।
पीटर Gfader

ओह, अब मैं इसे प्राप्त करता हूं, आप सभी उल्लिखित तीन विचारों से बचना चाहते हैं। ऐसा लग रहा था कि आप मॉनिटर का उपयोग करेंगे लेकिन लॉक / म्यूटेक्स का उपयोग नहीं करेंगे।
मफू

कभी भी System.Collections.Concurrent का उपयोग न करें। वे दौड़ की स्थिति का एक मुख्य स्रोत हैं, और कॉलर्स थ्रेड को भी ब्लॉक करते हैं।
अलेक्जेंडर डेनिलोव

-2

ज्यादातर मामलों में आपको ताले (= मॉनिटर्स) या म्यूटेक्स / सेमाफोर का उपयोग नहीं करना चाहिए । वे सभी वर्तमान थ्रेड को ब्लॉक करते हैं।

और आपको निश्चित रूप से कक्षाओं का उपयोग नहीं करना चाहिए System.Collections.Concurrent - वे दौड़ की स्थिति का मुख्य स्रोत हैं क्योंकि कई संग्रह के बीच लेनदेन का समर्थन नहीं करते हैं, और वर्तमान थ्रेड को भी ब्लॉक करते हैं।

आश्चर्यजनक रूप से .NET में सिंक्रनाइज़ेशन के लिए प्रभावी तंत्र नहीं है।

मैंने सी # पर जीसीडी ( दुनिया) से सीरियल कतार लागू की Objc/Swift- बहुत हल्के, न कि सिंक्रनाइज़ेशन टूल जो थ्रेड पूल का उपयोग करता है, परीक्षणों के साथ।

यह ज्यादातर मामलों में कुछ भी सिंक्रनाइज़ करने का सबसे अच्छा तरीका है - डेटाबेस एक्सेस (हेलो साइक्लाइट) से लेकर बिजनेस लॉजिक तक।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.