अपवाद है कि अलग धागे में फेंक दिया है


110

मेरी एक विधि ( Method1) एक नया धागा पैदा करती है। वह थ्रेड एक विधि को निष्पादित करता है ( Method2) और एक्सपेक्टेशन के दौरान एक अपवाद फेंक दिया जाता है। मुझे कॉलिंग विधि पर उस अपवाद जानकारी को प्राप्त करने की आवश्यकता है ( Method1)

क्या कोई अपवाद है Method1जो मैं इस अपवाद को पकड़ सकता हूं जिसमें फेंक दिया गया है Method2?

जवाबों:


182

में नेट 4 और ऊपर, आप उपयोग कर सकते हैं Task<T>नया धागा बनाने के बजाय वर्ग। फिर आप .Exceptionsअपने कार्य ऑब्जेक्ट पर संपत्ति का उपयोग करके अपवाद प्राप्त कर सकते हैं । इसे करने के 2 तरीके हैं:

  1. एक अलग विधि में: // आप कुछ कार्य के थ्रेड में अपवाद को संसाधित करते हैं

    class Program
    {
        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(Test);
            task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
            task.Start();
            Console.ReadLine();
        }
    
        static int Test()
        {
            throw new Exception();
        }
    
        static void ExceptionHandler(Task<int> task)
        {
            var exception = task.Exception;
            Console.WriteLine(exception);
        }
    }
    
  2. उसी विधि में: // आप कॉलर के धागे में अपवाद की प्रक्रिया करते हैं

    class Program
    {
        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(Test);
            task.Start();
    
            try
            {
                task.Wait();
            }
            catch (AggregateException ex)
            {
                Console.WriteLine(ex);    
            }
    
            Console.ReadLine();
        }
    
        static int Test()
        {
            throw new Exception();
        }
    }
    

ध्यान दें कि आपको जो अपवाद मिलता है वह है AggregateException। सभी वास्तविक अपवाद ex.InnerExceptionsसंपत्ति के माध्यम से उपलब्ध हैं।

में .NET 3.5 आप निम्नलिखित कोड का उपयोग कर सकते हैं:

  1. // आप बच्चे के धागे में अपवाद की प्रक्रिया करते हैं

    class Program
    {
        static void Main(string[] args)
        {
            Exception exception = null;
            Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), Handler));
            thread.Start();            
    
            Console.ReadLine();
        }
    
        private static void Handler(Exception exception)
        {        
            Console.WriteLine(exception);
        }
    
        private static void SafeExecute(Action test, Action<Exception> handler)
        {
            try
            {
                test.Invoke();
            }
            catch (Exception ex)
            {
                Handler(ex);
            }
        }
    
        static void Test(int a, int b)
        {
            throw new Exception();
        }
    }
    
  2. या // आप कॉलर के थ्रेड में अपवाद की प्रक्रिया करते हैं

    class Program
    {
        static void Main(string[] args)
        {
            Exception exception = null;
            Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), out exception));
    
            thread.Start();            
    
            thread.Join();
    
            Console.WriteLine(exception);    
    
            Console.ReadLine();
        }
    
        private static void SafeExecute(Action test, out Exception exception)
        {
            exception = null;
    
            try
            {
                test.Invoke();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
        }
    
        static void Test(int a, int b)
        {
            throw new Exception();
        }
    }
    

क्षमा करें, लेकिन मैं यह उल्लेख करना भूल गया कि मैं .NET 3.5 का उपयोग कर रहा हूं। मेरी समझ के अनुसार टास्क 4.0 चीज़ है?
सिल्वरलाइट छात्र

2
@SilverlightStudent ठीक है, मैंने आपकी आवश्यकताओं को पूरा करने के लिए मेरे उत्तर को अपडेट किया।
ऑक्सिलुमिन

@oxilumin: धन्यवाद और बहुत सराहना की। एक और फॉलोअप सवाल। यदि आपका परीक्षण () विधि कुछ तर्क भी लेती है, तो आप उन तर्कों के लिए SafeExecute विधि को कैसे संशोधित करेंगे?
सिल्वरलाइट छात्र

2
@SilverlightStudent इस मामले में मैं के बजाय एक भेड़ का बच्चा पारित करेंगे Test। जैसे() => Test(myParameter1, myParameter2)
ऑक्सिलुमिन

2
@SilverlightStudent: अपडेट किया गया।
ऑक्सिलुमिन

9

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


आपके प्रतिक्रिया के लिए धन्येवाद। इसलिए यदि Method1 Class1 का हिस्सा है और मेरे पास उस कक्षा में टाइप अपवाद का एक चर है। जब भी मेथड 2 एक अपवाद फेंकता है, यह क्लास 1 में भी उस अपवाद चर को सेट करता है। क्या यह एक उचित डिजाइन की तरह लगता है? क्या इस परिदृश्य को संभालने का कोई सर्वोत्तम अभ्यास तरीका है?
सिल्वरलाइट स्टूडेंट

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

0

विभिन्न थ्रेड्स के बीच डेटा साझा करने की सबसे सरल विधि shared dataइस प्रकार है (कुछ छद्म कोड है):

class MyThread
{
   public string SharedData;

   public void Worker()
   {
      ...lengthy action, infinite loop, etc...
      SharedData = "whatever";
      ...lengthy action...
      return;
   }
}

class Program
{
   static void Main()
   {
      MyThread m = new MyThread();
      Thread WorkerThread = new Thread(m.Worker);
      WorkerThread.Start();

      loop//or e.g. a Timer thread
      {
         f(m.SharedData);
      }
      return;
   }
}

आप मल्टीथ्रेडिंग के बारे में इस अच्छे परिचय में इस विधि के बारे में पढ़ सकते हैं , हालाँकि, मैंने इस बारे में पढ़ना पसंद O'Reilly book C# 3.0 in a nutshellकिया, भाइयों में अल्बहारी (2007), जो Google पुस्तक पर भी स्वतंत्र रूप से उपलब्ध है, जैसे कि पुस्तक का नया संस्करण, क्योंकि इसमें थ्रेड पूलिंग, फोरग्राउंड बनाम बैकग्राउंड थ्रेड्स आदि भी शामिल हैं, जिनमें अच्छे और सरल उदाहरण कोड हैं। (डिस्क्लेमर: इस पुस्तक की मैं एक घिसी-पिटी कॉपी हूं)

यदि आप WinForms एप्लिकेशन बना रहे हैं, तो साझा डेटा का उपयोग विशेष रूप से आसान है, क्योंकि WinForm नियंत्रण थ्रेड-सुरक्षित नहीं हैं। कार्यकर्ता थ्रेड से वापस WinForm पर डेटा पास करने के लिए कॉलबैक का उपयोग करके Invoke()उस नियंत्रण थ्रेड को सुरक्षित बनाने के लिए मुख्य UI थ्रेड के साथ बदसूरत कोड की आवश्यकता होती है । इसके बजाय साझा किए गए डेटा का उपयोग करना, और एकल-थ्रेडेड System.Windows.Forms.Timer, Interval0.2 सेकंड के कम कहने के साथ , आप आसानी से कार्यकर्ता थ्रेड से नियंत्रण के बिना जानकारी भेज सकते हैं Invoke


0

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

    public Boolean? Dance(String name) {

        // Already on an STA thread, so just go for it
        if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) return DanceSTA(name);

        // Local variable to hold the caught exception until the caller can rethrow
        Exception lException = null;

        Boolean? lResult = null;

        // A gate to hold the calling thread until the called thread is done
        var lGate = new ManualResetEvent(false);

        var lThreadStart = new ThreadStart(() => {
            try {
                lResult = DanceSTA(name);
            } catch (Exception ex) {
                lException = ex;
            }
            lGate.Set();
        });

        var lThread = new Thread(lThreadStart);
        lThread.SetApartmentState(ApartmentState.STA);
        lThread.Start();

        lGate.WaitOne();

        if (lException != null) throw lException;

        return lResult;
    }

    public Boolean? DanceSTA(String name) { ... }

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

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