लॉक कैसे ठीक काम करता है?


526

मैं देखता हूं कि जो वस्तुएं सुरक्षित नहीं हैं उनका उपयोग करने के लिए हम कोड को इस तरह से लॉक के साथ लपेटते हैं:

private static readonly Object obj = new Object();

lock (obj)
{
    // thread unsafe code
}

तो क्या होता है जब कई थ्रेड्स समान कोड तक पहुँचते हैं (मान लेते हैं कि यह ASP.NET वेब अनुप्रयोग में चल रहा है)। क्या वे पंक्तिबद्ध हैं? यदि हां, तो वे कब तक इंतजार करेंगे?

ताले का उपयोग करने के कारण प्रदर्शन प्रभाव क्या है?


1
^ मृत लिंक, देखें: jonskeet.uk/csharp/threads/index.html
इवान Pavičić

जवाबों:


447

lockबयान निम्न के सी # 3.0 द्वारा अनुवाद किया है:

var temp = obj;

Monitor.Enter(temp);

try
{
    // body
}
finally
{
    Monitor.Exit(temp);
}

C # 4.0 में यह बदल गया है और यह अब निम्नानुसार उत्पन्न होता है:

bool lockWasTaken = false;
var temp = obj;
try
{
    Monitor.Enter(temp, ref lockWasTaken);
    // body
}
finally
{
    if (lockWasTaken)
    {
        Monitor.Exit(temp); 
    }
}

आप यहाँ क्या Monitor.Enterकरता है के बारे में अधिक जानकारी पा सकते हैं । MSDN उद्धृत करने के लिए:

Enterपैरामीटर के रूप में पारित ऑब्जेक्ट पर मॉनिटर को प्राप्त करने के लिए उपयोग करें । यदि किसी अन्य थ्रेड ने Enter ऑब्जेक्ट पर निष्पादित किया है, लेकिन अभी तक संबंधित को निष्पादित नहीं किया है Exit, तो वर्तमान थ्रेड तब तक ब्लॉक होगा जब तक कि अन्य थ्रेड ऑब्जेक्ट को रिलीज़ नहीं करता। एक ही धागे को Enterअवरुद्ध किए बिना एक से अधिक बार आह्वान करना कानूनी है ; हालाँकि, Exitऑब्जेक्ट पर प्रतीक्षा कर रहे अन्य थ्रेड्स को कॉल करने के पहले समान संख्या में कॉल किया जाना चाहिए।

Monitor.Enterविधि असीम इंतजार करेंगे; यह समय नहीं होगा ।


15
MSDN के अनुसार "लॉक का उपयोग करना (C #) या SyncLock (विजुअल बेसिक) कीवर्ड को आमतौर पर मॉनिटर क्लास का उपयोग करके सीधे पसंद किया जाता है, क्योंकि लॉक या SyncLock दोनों अधिक संक्षिप्त होते हैं, और क्योंकि लॉक या SyncLock यह सुनिश्चित करता है कि अंतर्निहित मॉनिटर जारी किया गया है, यहां तक ​​कि यदि संरक्षित कोड अपवाद को फेंकता है, तो यह अंततः कीवर्ड के साथ पूरा होता है, जो अपवाद को फेंक दिए जाने की परवाह किए बिना अपने संबंधित कोड ब्लॉक को निष्पादित करता है। " msdn.microsoft.com/en-us/library/ms173179.aspx
Aiden Strydom

10
क्या बात है var temp = obj; लाइन। के बाद से यह सिर्फ एक रेफरी के साथ शुरू करने के लिए है, क्या अच्छा एक और कर रहा है?
प्रफुल्ल

11
@priehl यह objपूरे सिस्टम को गतिरोध के बिना उपयोगकर्ता को बदलने की अनुमति देता है ।
स्टीवन

7
@ जोयमन आखिरकार, हर भाषा की विशेषता वाक्यगत चीनी है। भाषा सुविधाएँ डेवलपर्स को अधिक उत्पादक बनाने और अनुप्रयोगों को अधिक बनाए रखने के बारे में हैं, जैसा कि लॉक फीचर भी है।
स्टीवन

2
सही बात। यह lock-स्टेटमेंट और मॉनिटर का संपूर्ण उद्देश्य है : ताकि आप एक थ्रेड में एक ऑपरेशन कर सकें, ताकि दूसरे थ्रेड को खराब होने की चिंता न हो।
डिजी एच। मफिन

285

आप जितना सोचते हैं, उससे ज्यादा सरल है।

Microsoft के अनुसार : दlock कीवर्ड यह सुनिश्चित करता है कि एक धागा कोड के एक महत्वपूर्ण खंड में प्रवेश नहीं करता है जबकि दूसरा धागा महत्वपूर्ण अनुभाग में है। यदि कोई अन्य थ्रेड लॉक किए गए कोड को दर्ज करने का प्रयास करता है, तो वह तब तक प्रतीक्षा करेगा, जब तक कि ऑब्जेक्ट जारी न हो जाए।

lockकीवर्ड कॉल Enterब्लॉक के शुरू में और Exitब्लॉक के अंत में। lockकीवर्ड वास्तव Monitorमें बैक एंड पर कक्षा को संभालता है ।

उदाहरण के लिए:

private static readonly Object obj = new Object();

lock (obj)
{
    // critical section
}

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


9
क्या हमें लॉक करने के लिए डमी ऑब्जेक्ट बनाना चाहिए या क्या हम संदर्भ में एक मौजूदा वैरिएबल को लॉक कर सकते हैं?
बैटमेसी

9
@batmaci - एक अलग निजी डमी ऑब्जेक्ट पर लॉक करने से आपको यह गारंटी मिलती है कि उस ऑब्जेक्ट में कोई और लॉक नहीं कर रहा है। यदि आप डेटा पर लॉक करते हैं और डेटा का वही टुकड़ा बाहर की ओर दिखाई देता है तो आप उस गारंटी को खो देते हैं।
उमर अब्बास

8
यदि एक से अधिक प्रक्रियाएं लॉक के रिलीज़ होने की प्रतीक्षा कर रही हों तो क्या होगा? क्या प्रतीक्षा प्रक्रियाएँ कतारबद्ध हैं ताकि वे FIFO क्रम में महत्वपूर्ण खंड को लॉक कर दें?
जस्टुअर्डो

@jstuardo - वे कतारबद्ध हैं, लेकिन आदेश FIFO होने की गारंटी नहीं है। इस लिंक को देखें: albahari.com/threading/part2.aspx
उमर अब्बास

से श्रेय नहीं दी कॉपी किया गया net-informations.com/faq/qk/lock.htm
मार्टिन पीटर्स

47

नहीं, वे कतारबद्ध नहीं हैं, वे सो रहे हैं

फॉर्म का एक लॉक स्टेटमेंट

lock (x) ... 

जहां x एक संदर्भ-प्रकार की अभिव्यक्ति है, ठीक इसके बराबर है

var temp = x;
System.Threading.Monitor.Enter(temp); 
try { ... } 
finally { System.Threading.Monitor.Exit(temp); }

आपको बस यह जानने की जरूरत है कि वे एक-दूसरे के लिए इंतजार कर रहे हैं, और केवल एक धागा लॉक ब्लॉक में प्रवेश करेगा, बाकी लोग इंतजार करेंगे ...

मॉनिटर पूरी तरह से .net में लिखा गया है इसलिए यह काफी तेज है, अधिक विवरण के लिए रिफ्लेक्टर के साथ क्लास मॉनिटर को भी देखें


6
ध्यान दें कि lockकथन के लिए उत्सर्जित कोड C # 4 में थोड़ा बदल गया है: blogs.msdn.com/b/ericlippert/archive/2009/03/06/…
ल्यूक

@ArsenMkrt, उन्हें "अवरुद्ध" स्थिति "कतार" में नहीं रखा गया है। मुझे लगता है कि स्लीप और ब्लॉक स्थिति के बीच कुछ अंतर हैं, है ना?
मोहनावेल

क्या फर्क पड़ता है @ मोहानवेल से?
आर्सेन मख्तारियान

1
यह सवाल नहीं था। सवाल "लॉक" कीवर्ड के बारे में था। मान लीजिए कि एक प्रक्रिया "लॉक" अनुभाग दर्ज करें। इसका मतलब है कि प्रक्रिया उस कोड को ब्लॉक कर देती है और कोई अन्य प्रक्रिया उस अनुभाग में प्रवेश करने में सक्षम नहीं हो सकती जब तक कि लॉक जारी नहीं किया जाता है। खैर .... अब, 2 और प्रक्रियाएं एक ही ब्लॉक में प्रवेश करने की कोशिश करती हैं। चूंकि यह "लॉक" कीवर्ड द्वारा सुरक्षित है, वे इस मंच में कही गई बात के अनुसार प्रतीक्षा करेंगे। जब पहली प्रक्रिया लॉक जारी करती है। क्या प्रक्रिया ब्लॉक में प्रवेश करती है? पहले वाले ने प्रवेश करने की कोशिश की या आखिरी वाले ने?
jstuardo

1
मुझे लगता है कि आपको प्रक्रिया के बजाय थ्रेड का मतलब है ... यदि हां, तो उत्तर की तुलना में कोई नहीं है, कोई गारंटी नहीं है कि कौन प्रवेश करेगा ... अधिक यहां stackoverflow.com/questions/4228864/…
आर्सेन मकर्त्चयन

29

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


11

प्रदर्शन प्रभाव आपके लॉक करने के तरीके पर निर्भर करता है। आप यहाँ अनुकूलन की एक अच्छी सूची पा सकते हैं: http://www.thinkingparallel.com/2007/07/31/10-ways-to-reduce-lock-contention-in-threaded-programs/

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


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

1
@ ल्यूक: कुछ उपयोग पैटर्न हैं जहां कम-लॉक कोड बहुत सरल और आसान हो सकता है [ do { oldValue = thing; newValue = updated(oldValue); } while (CompareExchange(ref thing, newValue, oldValue) != oldValue]। सबसे बड़ा खतरा यह है कि यदि आवश्यकताएं ऐसी तकनीकों से परे विकसित हो सकती हैं, तो उन्हें संभालने के लिए कोड को अनुकूलित करना कठिन हो सकता है।
सुपरकैट

लिंक टूट गया है।
कार्नरोज

8

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


8

इस lockकथन का अनुवाद Enterऔर Exitविधियों के कॉल के लिए किया गया है Monitor

lockबयान अनिश्चित काल के लिए इंतजार के लिए ताला लगा वस्तु जारी होने की होगी।


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