2011-08-15 25 views
8

पर सोते समय थ्रेड बाधित नहीं होता है, मैं एमएसडीएन पर देख रहा हूं और अंत में ब्लॉक के दौरान सोते समय थ्रेड को बाधित नहीं किया जा सकता है। मैंने सफलता के साथ निरस्त करने की कोशिश की है।अंततः

क्या अंत में ब्लॉक के दौरान सोते समय थ्रेड उठाने का कोई तरीका है?

Thread t = new Thread(ProcessSomething) {IsBackground = false}; 
t.Start(); 
Thread.Sleep(500); 
t.Interrupt(); 
t.Join(); 

private static void ProcessSomething() 
{ 
    try { Console.WriteLine("processing"); } 
    finally 
    { 
     try 
     { 
      Thread.Sleep(Timeout.Infinite); 
     } 
     catch (ThreadInterruptedException ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 
    } 
} 

हैरानी की बात है MSDN का दावा है धागा अंत में ब्लॉक में निरस्त किया गया जा सकता है: http://msdn.microsoft.com/en-us/library/aa332364(v=vs.71).aspx "। एक मौका है, जबकि एक अंत में ब्लॉक चल रहा है धागा गर्भपात कर सकता है, जो मामले में अंत में ब्लॉक निरस्त किया गया है नहीं है"

संपादित मैं के बाद से इस बताता है कि क्यों थ्रेड कभी कभी और बाधित नहीं किया जा सकता कर सकते हैं/गर्भपात में अंत में ब्लॉक को श्रेष्ठ उत्तर हंस Passant टिप्पणी पाते हैं। और वह तब होता है जब प्रक्रिया बंद हो जाती है। धन्यवाद

+3

मैं सवाल का जवाब पता नहीं है, लेकिन मैं * है * पता है कि एक सामान्य नियम के रूप में मैं से बचने के 'इंटरप्ट () 'धागे के बीच संकेत के लिए एक तंत्र के रूप में। बहुत अधिक अनुमानित एपीआई हैं- 'मॉनिटर', '{मैनुअल | ऑटो} रीसेट इवेंट ', आदि –

+0

मैं अंततः इंटरप्ट/एबॉर्ट काम नहीं करता है और एमएसडीएन विपरीत कहने पर क्यों कोई स्पष्टीकरण/दस्तावेज़ीकरण की तलाश में था। मेरा उदाहरण अधिक जटिल प्रकार का परामर्शदाता है और मैं अब सुझाव के रूप में इसे कमरांड के लिए पढ़ रहा हूं। – Marek

+3

दो प्रकार के थ्रेड एबॉर्ट्स हैं। दोस्ताना एक आखिरकार ब्लॉक में कोड को बाधित नहीं करेगा। असभ्य रूप से एक आक्रमण किया जाता है जब प्रक्रिया उस थ्रेड पर बंद हो जाती है जिसमें IsBackground सत्य के बराबर है या जब यह एक अनचाहे अपवाद पर समाप्त हो रहा है। अब इससे कोई फर्क नहीं पड़ता कि कोड कठोर रूप से बाधित हो गया है। –

उत्तर

8

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

इसके बजाय, ताकि धागे कर सकते हैं एक दूसरे के साथ सहयोग करने और इतने अवरुद्ध और शान से अनब्लॉक करने, जैसे संभाल एक संकेतन तंत्र का उपयोग करें:

private readonly AutoResetEvent ProcessEvent = new AutoResetEvent(false); 
    private readonly AutoResetEvent WakeEvent = new AutoResetEvent(false); 

    public void Do() 
    { 
     Thread th1 = new Thread(ProcessSomething); 
     th1.IsBackground = false; 
     th1.Start(); 

     ProcessEvent.WaitOne(); 

     Console.WriteLine("Processing started..."); 

     Thread th2 = new Thread(() => WakeEvent.Set()); 
     th2.Start(); 

     th1.Join(); 
     Console.WriteLine("Joined"); 
    } 

    private void ProcessSomething() 
    { 
     try 
     { 
      Console.WriteLine("Processing..."); 
      ProcessEvent.Set(); 
     } 
     finally 
     { 
      WakeEvent.WaitOne(); 
      Console.WriteLine("Woken up..."); 
     } 
    } 

अद्यतन

काफी एक दिलचस्प निम्न स्तर मुद्दा। हालांकि Abort() दस्तावेज है, Interrupt() बहुत कम है।

आपके प्रश्न का संक्षिप्त उत्तर नहीं है, आप Abort या Interrupt पर कॉल करके अंत में ब्लॉक में थ्रेड नहीं जगा सकते हैं।

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

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

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

अपवाद (कोई इरादा नहीं है) इसे Rude Aborts कहा जाता है। ये सीएलआर होस्टिंग पर्यावरण द्वारा उठाए गए ThreadAbortExceptions हैं। ये आखिरकार ब्लॉक कर सकते हैं और ब्लॉक को बाहर निकालने के लिए पकड़ सकते हैं, लेकिन सीईआर नहीं। उदाहरण के लिए, सीएलआर धागे के जवाब में रूड एबॉर्ट्स बढ़ा सकता है, जिसने अपने काम को बाहर करने के लिए बहुत लंबा समय लेने का फैसला किया है। SQL सर्वर CLR के भीतर कोई ऐपडोमेन या कोड निष्पादित करने का प्रयास करते समय। आपके विशेष उदाहरण में, जब आपका एप्लिकेशन बंद हो जाता है और ऐपडोमेन अनलोड हो जाता है, तो सीएलआर नींद के धागे पर एक अशिष्ट गर्भपात जारी करेगा क्योंकि ऐपडोमेन अनलोड लोडआउट होगा।

अंततः ब्लॉक में निरंतर अवरोध और बाधा उपयोगकर्ता कोड में नहीं होने वाली है, लेकिन दोनों मामलों के बीच थोड़ा अलग व्यवहार है।

बीच में बंद करें

जब एक अंत में ब्लॉक में एक धागे पर Abort बुला, बुला धागा अवरुद्ध है। यह documented है:

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

  1. बुला धागा एक Abort जारी लेकिन यहाँ ब्लॉक जब तक अंत में ब्लॉक से बाहर निकल गया है जाएगा:

बीच में बंद करें मामले में अगर नींद अनंत नहीं था Join कथन के लिए।

  • कैली थ्रेड का राज्य AbortRequested पर सेट है।
  • कैली सो रही है।
  • जब कैली जागता है, क्योंकि इसमें AbortRequested की स्थिति होती है तो यह आखिरकार ब्लॉक कोड निष्पादित करना जारी रखेगी और फिर "वाष्पीकरण" यानी बाहर निकलेंगी।
  • जब निरस्त धागा अंततः ब्लॉक छोड़ देता है: कोई अपवाद नहीं उठाया जाता है, अंत में ब्लॉक को निष्पादित करने के बाद कोई कोड नहीं होता है, और धागा का राज्य Aborted होता है।
  • कॉलिंग थ्रेड अनब्लॉक किया गया है, Join कथन जारी है और तुरंत कहा जाता है क्योंकि बुलाया गया थ्रेड निकल गया है।
  • तो एक अनंत नींद के साथ अपने उदाहरण को देखते हुए बुला धागा चरण 1

    इंटरप्ट

    बाधा मामले में पर हमेशा के लिए ब्लॉक अगर नींद अनंत नहीं था होगा:

    इतना अच्छी तरह से प्रलेखित नहीं ...

    1. बुला धागा एक Interrupt और को क्रियान्वित करने के लिए जारी जारी करेगा।
    2. कॉलिंग थ्रेड Join कथन पर अवरुद्ध होगा।
    3. कैली थ्रेड के पास अगले ब्लॉकिंग कॉल पर अपवाद बढ़ाने के लिए अपना राज्य सेट है, लेकिन महत्वपूर्ण रूप से यह आखिरकार ब्लॉक में है, इसलिए इसे अनब्लॉक नहीं किया गया है।
    4. कैली सो रही है।
    5. जब कैली जागता है, तो यह अंततः ब्लॉक को निष्पादित करना जारी रखेगा।
    6. जब बाधित थ्रेड अंततः ब्लॉक छोड़ देता है तो यह अगले ब्लॉकिंग कॉल पर ThreadInterruptedException फेंक देगा (नीचे कोड उदाहरण देखें)।
    7. बुला धागा "मिलती है" और के रूप में बुलाया धागा से बाहर निकल गया है, हालांकि, बिना क्रिया ThreadInterruptedException चरण 6 में अब प्रक्रिया चपटा है जारी है ...

    तो फिर एक अनंत नींद के साथ अपने उदाहरण को देखते हुए, बुला धागा हमेशा के लिए अवरुद्ध कर देगा, लेकिन कदम पर 2.

    सारांश

    इसलिए हालांकि Abort और Interrupt थोड़ा अलग व्यवहार है, वे बुलाया सूत्र में दोनों परिणाम हमेशा के लिए सो जाएगा, और बुला धागा हमेशा के लिए अवरुद्ध (मेंआपका उदाहरण)।

    केवल एक असभ्य बीच में बंद करें एक अंत में ब्लॉक से बाहर निकलने का अवरुद्ध धागा मजबूर कर सकते हैं, और इनमें से केवल CLR से ही उठाया जा सकता है (आप भी ThreadAbortException.ExceptionState लुढ़का करने के लिए प्रतिबिंब का उपयोग नहीं कर सकते हैं के रूप में यह AbortReason प्राप्त करने के लिए एक आंतरिक CLR कॉल करता है - वहां आसानी से बुराई होने का कोई मौका नहीं है ...)।

    सीएलआर उपयोगकर्ता कोड को अंततः ब्लॉकों को अपने स्वयं के अच्छे से बाहर निकलने के कारण रोकता है - यह दूषित राज्य को रोकने में मदद करता है।

    Interrupt साथ थोड़ा अलग व्यवहार का एक उदाहरण के लिए:

    internal class ThreadInterruptFinally 
    { 
        public static void Do() 
        { 
         Thread t = new Thread(ProcessSomething) { IsBackground = false }; 
         t.Start(); 
         Thread.Sleep(500); 
         t.Interrupt(); 
         t.Join(); 
        } 
    
        private static void ProcessSomething() 
        { 
         try 
         { 
          Console.WriteLine("processing"); 
         } 
         finally 
         { 
          Thread.Sleep(2 * 1000); 
         } 
    
         Console.WriteLine("Exited finally..."); 
    
         Thread.Sleep(0); //<-- ThreadInterruptedException 
        } 
    } 
    
    +0

    +1 ग्रेट उत्तर। –

    4

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

    इसके बजाय, सहकारी डिजाइन का उपयोग करें। यदि Sleep पर कॉल करने के बजाय, थ्रेड को बाधित किया जाना चाहिए, तो समय प्रतीक्षा का उपयोग करें। Interrupt को कॉल करने के बजाय थ्रेड उस चीज को सिग्नल करता है जो थ्रेड के लिए प्रतीक्षा करता है।

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