2010-10-13 24 views
24

मैंने अभी "सी # 4.0 में संक्षेप में पढ़ना समाप्त कर दिया है" (O'Reilly) और मुझे लगता है कि यह प्रोग्रामर के लिए सी # पर स्विच करने के इच्छुक एक महान पुस्तक है, लेकिन यह मुझे आश्चर्यचकित कर दिया। मेरी समस्या using कथन की परिभाषा है। पुस्तक (पी। 138) के अनुसारक्या सी # का उपयोग कथन का उपयोग कर सुरक्षित है?

using (StreamReader reader = File.OpenText("file.txt")) { 
    ... 
} 

ठीक करने के बराबर है:

StreamReader reader = File.OpenText("file.txt"); 
try { 
    ... 
} finally { 
    if (reader != null) 
     ((IDisposable)reader).Dispose(); 
} 

मान लीजिए, तथापि, कि यह सच है और कहा कि इस कोड को एक अलग थ्रेड में मार डाला गया है। यह धागा अब thread.Abort() के साथ निरस्त कर दिया गया है, इसलिए ThreadAbortException फेंक दिया गया है और मान लीजिए कि पाठक को प्रारंभ करने के बाद और try..finally खंड दर्ज करने से पहले थ्रेड ठीक है। इसका मतलब यह होगा कि पाठक का निपटारा नहीं किया गया है!

सम्भावित समाधान इस तरह से कोड करने के लिए होगा:

StreamReader reader = null; 
try { 
    reader = File.OpenText("file.txt"); 
    ... 
} finally { 
    if (reader != null) 
     ((IDisposable)reader).Dispose(); 
} 

यह गर्भपात सुरक्षित होगा।

मेरे सवालों के लिए अब:

  1. किताब सही के लेखक हैं और using बयान गर्भपात-सुरक्षित नहीं है या वे गलत हैं और यह मेरी दूसरी समाधान में तरह बर्ताव करता है?
  2. यदि using पहले संस्करण (abort-safe नहीं) के बराबर है, तो finally में यह क्यों जांचता है?
  3. पुस्तक के अनुसार (पृष्ठ 856), ThreadAbortException प्रबंधित कोड में कहीं भी फेंक दिया जा सकता है। लेकिन शायद अपवाद हैं और पहला संस्करण निरस्त-सुरक्षित है?

संपादित करें: मुझे पता है कि thread.Abort() का उपयोग कर अच्छा अभ्यास माना जाता है। मेरी रुचि पूरी तरह सैद्धांतिक है: using कथन बिल्कुल व्यवहार कैसे करता है?

+0

क्या होगा यदि आपको 'निपटान' कॉल से पहले 'अंत में' ब्लॉक के अंदर 'थ्रेडएबॉर्ट अपवाद' मिलता है? – liori

+12

आश्चर्यचकित करना कि थ्रेड को कॉल करते समय व्यवहार क्या होता है।Abort' थोड़ा सोच रहा है कि क्या आपकी कार पर एयर बैग ** वास्तव में ** काम करते हैं। अगर आपको पता होना चाहिए, तो आपको पहले से ही बहुत बड़ी समस्या मिली है। –

+0

बिल्कुल .... आप दस लाख अलग-अलग समय के साथ आ सकते हैं जहां बुरी चीजें होती हैं। असल में, एक थ्रेडअबॉर्ट एक संकेत है कि कुछ बहुत ही भयानक पहले से ही हुआ है। एक गैर-डिस्प्ले फ़ाइल रीडर उस बिंदु पर आपकी चिंताओं का कम से कम है। – Clyde

उत्तर

16

पुस्तक के साथी वेब साइट धागे here निरस्त किया जा रहा बारे में अधिक जानकारी।

संक्षेप में है, पहला अनुवाद सही है (आप आईएल को देख) द्वारा करने के लिए कह सकते हैं।

जवाब आपके दूसरा सवाल यह है कि ऐसे परिदृश्य हो सकते हैं जहां चर वैध रूप से शून्य हो सकता है। उदाहरण के लिए मंजूरी, GetFoo() अशक्त यहाँ वापस आ सकते हैं, जिसमें आप एक NullReferenceException निहित अंत में ब्लॉक में फेंक दिया नहीं चाहता:

using (var x = GetFoo()) 
{ 
    ... 
} 

अपने तीसरे सवाल का जवाब करने के लिए, एक ही रास्ता बीच में बंद करें सुरक्षित बनाने के लिए (यदि आप ' फ्रेमवर्क कोड को फिर से कॉल करना) बाद में AppDomain को फाड़ना है। यह वास्तव में कई मामलों में एक व्यावहारिक समाधान है (जब भी आप चल रहे क्वेरी को रद्द करते हैं तो यह ठीक है LINQPad करता है)।

+0

ग्रेट आलेख, यह वही है जो मैं ढूंढ रहा था। और खुद लेखक से! धन्यवाद! लेखक से उत्तर प्राप्त करने के लिए – DzinX

+0

+1 – hackerhasid

6

Thread.Abort बहुत बुरी जुजू है; अगर लोग कॉल कर रहे हैं कि आप में पहले से ही परेशानी (अप्राप्य ताले आदि) में हैं। Thread.Abort वास्तव में एक बीमार प्रक्रिया को अपमानित करने के स्कैनरियो तक ही सीमित होना चाहिए।

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

null चेक करें; क्या होगा अगर File.OpenTextnull लौटा? ठीक है, यह नहीं होगा लेकिन कंपाइलर यह नहीं जानता है।

+0

+1: आप सही हैं, न केवल कन्स्ट्रक्टर का उपयोग 'उपयोग' कथन में किया जा सकता है। धन्यवाद! – DzinX

+0

@DzinX - भी, रचनाकार शून्य वापस कर सकते हैं। और नहीं * बस * 'Nullable ' के लिए - कक्षाओं के लिए भी। सच में नहीं। –

+0

यह दिलचस्प है, कैसे? – DzinX

7

वास्तव में आपके दो परिदृश्यों के बीच कोई अंतर नहीं है - दूसरे में, ThreadAbort अभी भी OpenText पर कॉल के बाद हो सकता है, लेकिन परिणाम को पाठक को सौंपा गया है।

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

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

2

भाषा का नमूना स्पष्ट रूप से बताता है कि पहला व्यक्ति सही है।

http://msdn.microsoft.com/en-us/vcsharp/aa336809.aspx एमएस युक्ति (वर्ड दस्तावेज़)
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf ECMA युक्ति

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

लेकिन आपको थैले गर्भपात का उपयोग नहीं करना चाहिए क्योंकि यह आसानी से एपडोमेन की स्थिति को दूषित कर सकता है। तो अगर आप एक एपडोमेन को अनलोड करते हैं तो केवल धागे को छोड़ दें।

+0

धन्यवाद, यह दस्तावेज़ वास्तव में उपयोगी है। – DzinX

4

थोड़ा ऑफटॉपिक लेकिन थ्रेड गर्भपात के दौरान लॉक स्टेटमेंट का व्यवहार भी दिलचस्प है। जबकि ताला के बराबर है:

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

यह (x86 घबराना द्वारा) की गारंटी है कि धागा बीच में बंद करें Monitor.Enter और कोशिश बयान के बीच नहीं होती है।
http://blogs.msdn.com/b/ericlippert/archive/2007/08/17/subtleties-of-c-il-codegen.aspx

उत्पन्न आईएल कोड .net 4 में अलग हो रहा है:
http://blogs.msdn.com/b/ericlippert/archive/2009/03/06/locks-and-exceptions-do-not-mix.aspx

+0

दिलचस्प। क्या आपके पास कोई संदर्भ है जो इसे बताता है? मुझे भाषा विनिर्देश में नहीं मिला। – DzinX

+0

@dzinx @codeinchaos - एरिक लिपर्ट ब्लॉग देखें। यह लंबित spec संस्करण में अपडेट किया गया है (यदि पहले से नहीं है)। इसके अलावा, घटनाओं को भी ओवरहाल किया जाता है। –

0

पूर्व वास्तव में वास्तव में बाद के बराबर है।

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

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

उसने कहा, एक बार जब आप थ्रेडएबॉर्ट में हैं, तो सफाई करने की कोशिश क्यों परेशान करते हैं? आप वैसे भी मौत के थ्रो में हैं।

2

आप गलत समस्या पर ध्यान केंद्रित कर रहे हैं। ThreadAbortException ओपनटेक्स्ट() विधि को निरस्त करने की संभावना है। आप उम्मीद कर सकते हैं कि यह उस के लिए लचीला है लेकिन यह नहीं है। फ्रेमवर्क विधियों में ऐसे खंडों को आजमाएं/पकड़ें जो थ्रेड निरस्त करने से निपटने का प्रयास करते हैं।

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

-2

आखिरकार कथन हमेशा निष्पादित किया जाता है, MSDN कहता है "आखिरकार कोड निष्पादन के एक कथन ब्लॉक की गारंटी के लिए उपयोग किया जाता है, चाहे पूर्ववर्ती प्रयास ब्लॉक कैसे निकलता है।"

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

+0

यह कैसे मदद करता है? अगर "पाठक" के असाइनमेंट से पहले गर्भपात होता है (लेकिन फ़ाइल खोले जाने के बाद) यह शून्य हो जाएगा और अंत में कथन कुछ भी नहीं करता है। – adrianm

+2

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

+0

@Eric मेरे विपक्ष में (और कुछ क्विक टेस्ट इसके साथ बहस करता है) जैसे ही एक कोशिश ब्लॉक में केवल एक पंक्ति निष्पादक है, आप सुनिश्चित कर सकते हैं कि आखिरकार ब्लॉक का उपयोग किया जाता है, इससे कोई फर्क नहीं पड़ता कि क्या होता है। – Tokk

1

क्या पुस्तक के लेखक सही हैं और उपयोग कथन निरस्त नहीं हैं या वे गलत हैं और यह मेरे दूसरे समाधान में व्यवहार करता है?

पुस्तक के अनुसार (पृष्ठ 856), थ्रेडएबॉर्ट अपवाद को प्रबंधित कोड में कहीं भी फेंक दिया जा सकता है। लेकिन शायद अपवाद हैं और पहला संस्करण निरस्त-सुरक्षित है?

लेखक सही हैं। using ब्लॉक निरस्त-सुरक्षित नहीं है। आपका दूसरा समाधान भी निरस्त नहीं है, संसाधन अधिग्रहण के बीच में थ्रेड को निरस्त किया जा सकता है।

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

एक Thread.Abort केवल कोड के अंदर विवश निष्पादन क्षेत्र (CERs), finally ब्लॉक, catch ब्लॉक, स्थिर कंस्ट्रक्टर्स, और अप्रबंधित कोड को चलाने के लिए इंतजार करेंगे। तो यह एक बीच में बंद करें-सुरक्षित समाधान (केवल अधिग्रहण और संसाधन के निपटान के संबंध) है:

StreamReader reader = null; 
try { 
    try { } 
    finally { reader = File.OpenText("file.txt"); } 
    // ... 
} 
finally { 
    if (reader != null) reader.Dispose(); 
} 

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

यदि उपयोग पहले संस्करण (अपरिवर्तनीय नहीं) के बराबर है, तो आखिर में यह शून्य की जांच क्यों करता है?

अशक्त के लिए जांच की जा रही using पैटर्न null संदर्भ की उपस्थिति में सुरक्षित बनाता है।

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

  • कोई संबंधित समस्या नहीं^_^