programing tip

다른 스레드에서 발생한 예외 포착

itbloger 2020. 8. 12. 07:52
반응형

다른 스레드에서 발생한 예외 포착


내 방법 중 하나 ( Method1)는 새 스레드를 생성합니다. 해당 스레드는 메서드 ( Method2)를 실행하고 예외 중에 예외가 발생합니다. 호출 메서드 ( Method1) 에 대한 예외 정보를 가져와야합니다.

어떻게 Method1든 던져진 이 예외를 잡을 수 Method2있습니까?


에서 .NET 4 이상, 당신은 사용할 수 있습니다 Task<T>새 스레드를 만드는 대신 클래스를. 그런 다음 .Exceptions작업 개체의 속성을 사용하여 예외를 가져올 수 있습니다 . 두 가지 방법이 있습니다.

  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();
        }
    }
    

Method1에서 예외를 포착 할 수 없습니다. 그러나 Method2에서 예외를 포착하여 원래 실행 스레드가 읽고 작업 할 수있는 변수에 기록 할 수 있습니다.


서로 다른 스레드간에 데이터를 공유하는 가장 간단한 방법은 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;
   }
}

You can read about this method in this nice introduction about multithreading, however, I preferred to read about this in the O'Reilly book C# 3.0 in a nutshell, by the brothers Albahari (2007), which is also freely accessible on Google Books, just like the newer version of the book, because it also covers thread pooling, foreground versus background threads, etc etc, with nice and simple example code. (Disclaimer: I own a worn-out copy of this book)

In case you are making a WinForms application, the use of shared data is especially handy, because the WinForm controls are not thread-safe. Using a callback to pass data from the worker thread back to a WinForm control the main UI thread needs ugly code with Invoke() to make that control thread-safe. Using shared data instead, and the single-threaded System.Windows.Forms.Timer, with a short Interval of say 0.2 seconds, you can easily send information from the worker thread to the control without Invoke.


I had a particular problem in that I wanted to use items, containing controls, from an integration test suite, so have to create an STA thread. The code I ended up with is as follows, put here in case others have the same issue.

    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) { ... }

This is a direct paste of the code as-is. For other uses I would recommend supplying an action or function as a parameter and invoking that on the thread instead of hard-coding the called method.

참고URL : https://stackoverflow.com/questions/5983779/catch-exception-that-is-thrown-in-different-thread

반응형