क्या एक बंद वस्तु बंद रहती है अगर कोई अपवाद इसके अंदर होता है?


85

एसी # थ्रेडिंग ऐप में, यदि मैं किसी ऑब्जेक्ट को लॉक करने के लिए था, तो हम एक कतार कहते हैं, और यदि कोई अपवाद होता है, तो क्या ऑब्जेक्ट लॉक हो जाएगा? यहाँ छद्म कोड है:

int ii;
lock(MyQueue)
{
   MyClass LclClass = (MyClass)MyQueue.Dequeue();
   try
   {
      ii = int.parse(LclClass.SomeString);
   }
   catch
   {
     MessageBox.Show("Error parsing string");
   }
}

जैसा कि मैं इसे समझता हूं, कैच के बाद कोड निष्पादित नहीं करता है - लेकिन मैं सोच रहा हूं कि क्या लॉक को मुक्त किया जाएगा।


1
एक अंतिम विचार के रूप में (अपडेट देखें) - आपको संभवतः केवल डॉक्यू की अवधि के लिए लॉक को पकड़ना चाहिए ... लॉक के बाहर की प्रोसेसिंग करें ।
मार्क Gravell

1
कैच के बाद कोड निष्पादित होता है क्योंकि अपवाद को संभाला जाता है
cjk 12

धन्यवाद मुझे याद किया जाना चाहिए कि क्या मुझे इस प्रश्न को हटाना चाहिए?
Vort3x

4
ऐसा लगता है कि नमूना कोड इस प्रश्न के लिए अच्छा नहीं है, लेकिन प्रश्न बहुत ही मान्य है।
साल्वाडोरगोमेज़

C # डिज़ाइनर द्वारा - Lock & Exception
Jivan

जवाबों:


88

प्रथम; क्या आपने TryParse पर विचार किया है?

in li;
if(int.TryParse(LclClass.SomeString, out li)) {
    // li is now assigned
} else {
    // input string is dodgy
}

ताला 2 कारणों से जारी किया जाएगा; सबसे पहले, lockअनिवार्य रूप से है:

Monitor.Enter(lockObj);
try {
  // ...
} finally {
    Monitor.Exit(lockObj);
}

दूसरा; आप आंतरिक अपवाद को पकड़ते हैं और फिर से नहीं फेंकते हैं, इसलिए lockवास्तव में कभी अपवाद नहीं दिखता है। बेशक, आप मैसेजबॉक्स की अवधि के लिए लॉक को पकड़ रहे हैं, जो एक समस्या हो सकती है।

तो यह सभी लेकिन सबसे घातक अप्राकृतिक अपरिवर्तनीय अपवादों में जारी किया जाएगा।


14
मुझे इस प्रयास के बारे में पता है, लेकिन यह वास्तव में मेरे प्रश्न के लिए प्रासंगिक नहीं है। यह सवाल समझाने के लिए सरल कोड था - पार्स के बारे में सही चिंता नहीं। कृपया किसी भी कोड के साथ पार्स को बदलें जो पकड़ को मजबूर करेगा और आपको आरामदायक बना देगा।
खादी

13
कैसे के बारे में नए अपवाद फेंक ("उदाहरण के प्रयोजनों के लिए"); ;-p
मार्क Gravell

1
सिवाय इसके और के TheadAbortExceptionबीच में होने पर : blogs.msdn.com/ericlippert/archive/2009/03/06/…Monitor.Entertry
Igal Tabachnik

2
"घातक भयावह अपरिवर्तनीय अपवाद" धाराओं को पार करने की तरह।
फिल कूपर

98

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

इसे इस तरह से देखें: मान लें कि आपके पास दरवाजे पर ताला लगा हुआ एक बाथरूम है और बाहर इंतजार कर रहे लोगों की कतार है। बाथरूम में एक बम गिरा, जिससे उस व्यक्ति की मौत हो गई। आपका सवाल है "उस स्थिति में ताला स्वतः ही अनलॉक हो जाएगा ताकि अगला व्यक्ति बाथरूम में जा सके?" हाँ यह होगा। ये अच्छी बात नहीं है। एक बम बस वहाँ से चला गया और किसी को मार डाला! नलसाजी शायद नष्ट हो गया है, घर अब संरचनात्मक रूप से ध्वनि नहीं है, और वहां एक और बम हो सकता है । सही बात यह है कि हर किसी को जल्दी से जल्दी बाहर निकालो और पूरे घर को ध्वस्त कर दो।

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

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

कोई फर्क नहीं पड़ता कि आप इसे कैसे काटते हैं, ताला के अंदर एक अपवाद बुरी खबर है । पूछने के लिए सही सवाल यह नहीं है "क्या अपवाद की स्थिति में मेरा ताला साफ हो जाएगा?" पूछने के लिए सही सवाल यह है कि "मैं यह कैसे सुनिश्चित करूं कि एक ताला के अंदर कोई अपवाद नहीं है? और अगर वहाँ है, तो मैं अपना कार्यक्रम कैसे बनाऊं ताकि उत्परिवर्तन पिछले अच्छे राज्यों में वापस आ जाए?"


18
IMO को लॉक करने के लिए यह मुद्दा बहुत ओर्थोगोनल है। यदि आपको एक अपेक्षित अपवाद मिलता है, तो आप ताले सहित सब कुछ साफ करना चाहते हैं। और अगर आपको एक अप्रत्याशित अपवाद मिलता है, तो आपके पास ताले के साथ या बिना एक समस्या है।
कोडइन्चोज

10
मुझे लगता है कि ऊपर वर्णित स्थिति एक सामान्यता है। कभी-कभी अपवाद भयावह घटनाओं का वर्णन करते हैं। कभी-कभी वे नहीं करते हैं। हर एक कोड में उनका अलग-अलग इस्तेमाल करता है। यह पूरी तरह से मान्य है कि एक अपवाद एक असाधारण लेकिन गैर-विनाशकारी घटना का एक संकेत है - अपवाद = प्रलय, प्रक्रिया को समाप्त करने का मामला बहुत विशिष्ट है। तथ्य यह है कि एक भयावह घटना हो सकती है सवाल की वैधता से दूर नहीं करता है - विचार की एक ही ट्रेन आपको किसी भी अपवाद को संभालने के लिए कभी नहीं ले सकती है, जिस स्थिति में प्रक्रिया से बाहर किया जाएगा ...
गेरासिमोस आर

1
@GerasimosR: वास्तव में। जोर देने के लिए दो बिंदु। सबसे पहले, अपवाद सौम्य होने तक विनाशकारी माना जाना चाहिए। दूसरा, यदि आपको एक बंद क्षेत्र से बाहर फेंका गया एक सौम्य अपवाद मिल रहा है, तो बंद क्षेत्र संभवतः बुरी तरह से डिज़ाइन किया गया है; यह शायद लॉक के अंदर बहुत अधिक काम कर रहा है।
एरिक लिपिपर्ट

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

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

43

हाँ, यह ठीक से जारी होगा; अंत में / के साथ / के lockरूप में कार्य करता है , इसलिए इससे कोई फर्क नहीं पड़ता कि आप इससे बाहर कैसे निकलेंगे। साइड-नोट के रूप में, सबसे अच्छा बचा जाता है, क्योंकि यह स्टैक-ट्रेस को नुकसान पहुंचाता है ; बेहतर यह पकड़ने के लिए नहीं है सब पर उपयोग:, या वैकल्पिक रूप के बजाय जो एक फिर से फेंक करता है।tryfinallyMonitor.Exit(myLock)catch(... e) {throw e;}ethrow;throw e;

यदि आप वास्तव में जानना चाहते हैं, तो C # 4 / .NET 4 में एक लॉक है:

{
    bool haveLock = false;
    try {
       Monitor.Enter(myLock, ref haveLock);
    } finally {
       if(haveLock) Monitor.Exit(myLock);
    }
} 

14

"एक लॉक स्टेटमेंट को मॉनिटर.इंटर को कॉल करने के लिए संकलित किया जाता है, और फिर एक कोशिश ... अंत में ब्लॉक। अंत में ब्लॉक में। मॉनिटर। एक्सिट कहा जाता है।

X86 और x64 दोनों के लिए JIT कोड पीढ़ी यह सुनिश्चित करती है कि एक मॉनिटर के बीच एक थ्रेड एबॉर्ट नहीं हो सकता है। एक कॉल और एक कोशिश ब्लॉक जो तुरंत इसका अनुसरण करता है। "

से लिया गया: यह साइट


1
कम से कम एक मामला है जहां यह सच नहीं है: थ्रेड डिबग मोड में थ्रेड एबॉर्शन पर 4 से पहले संस्करण। कारण यह है कि सी # कंपाइलर Monitor.Enterऔर के बीच एक एनओपी सम्मिलित करता है try, ताकि "तुरंत" की स्थिति JIT का उल्लंघन किया जाता है।
कोडइन्चोस

6

आपका लॉक ठीक से रिलीज़ हो जाएगा। lockइस तरह एक कार्य:

try {
    Monitor.Enter(myLock);
    // ...
} finally {
    Monitor.Exit(myLock);
}

और finallyब्लॉकों को निष्पादित करने की गारंटी दी जाती है, चाहे आप tryब्लॉक को कैसे छोड़ें ।


वास्तव में, कोई कोड निष्पादित करने के लिए "गारंटीकृत" नहीं है (आप उदाहरण के लिए पावर केबल खींच सकते हैं), और वह काफी नहीं है जो 4.0 में लॉक दिखता है - यहां देखें
मार्क ग्रेवेल

1
@MarcGravell: मैंने उन दो सटीक बिंदुओं के बारे में दो फ़ुटनोट लगाने के बारे में सोचा। और फिर मैं यह नहीं ज्यादा बात :) लगा होगा
Ry-

1
@MarcGravel: मुझे लगता है कि हर कोई मानता है कि कोई 'प्लग को खींचने' की स्थिति के बारे में बात नहीं कर रहा है, क्योंकि यह ऐसा कुछ नहीं है, जिस पर प्रोग्रामर का कोई नियंत्रण न हो :)
Vort3x

5

बस मार्क के उत्कृष्ट उत्तर के लिए थोड़ा जोड़ने के लिए।

इस तरह की स्थिति lockकीवर्ड के अस्तित्व का बहुत कारण हैं । यह डेवलपर्स को यह सुनिश्चित करने में मदद करता है कि finallyब्लॉक में लॉक जारी किया गया है।

यदि आप टाइमआउट का समर्थन करने के लिए उपयोग करने के लिए मजबूर हैं Monitor.Enter/ हैं Exit, तो आपको अपवाद के मामले में लॉक की उचित रिलीज सुनिश्चित करने के लिए कॉल को ब्लॉक Monitor.Exitमें रखना सुनिश्चित करना चाहिए finally

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