2012-01-08 15 views
8

Jestem zaznajomiony z faktem, że wyjątek wyrzucony w wątku normalnie nie może zostać przechwycony w innym wątku. Jak mogę przenieść błąd do głównego wątku?Jak przekazać wyjątek jawnie do głównego wątku w C#

public static void Main() 
{ 
    new Thread (Go).Start(); 
} 

static void Go() 
{ 
    try 
    { 
    // ... 
    throw null; // The NullReferenceException will get caught below 
    // ... 
    } 
    catch (Exception ex) 
    { 
    // Typically log the exception, and/or signal another thread 
    // that we've come unstuck 
    // ... 
    } 
} 

Odpowiedz

6

Jeśli używasz .NET 4. Są lepsze sposoby, aby to zrobić z Tasks, ale zakładając, że trzeba użyć Threads ...

Jeśli przykładem jest aplikacja konsoli, wówczas Główna metoda wyjdzie , prawdopodobnie przed wykonaniem Go. Więc twój "główny wątek" może nie istnieć, gdy zostanie zgłoszony wyjątek. Aby to zatrzymać, potrzebujesz synchronizacji.

Coś jak to powinno zrobić:

static Exception _ThreadException = null; 

public static void Main() 
{ 
    var t = new Thread (Go); 
    t.Start(); 

    // this blocks this thread until the worker thread completes 
    t.Join(); 

    // now see if there was an exception 
    if (_ThreadException != null) HandleException(_ThreadException); 
} 

static void HandleException(Exception ex) 
{ 
    // this will be run on the main thread 
} 

static void Go() 
{ 
    try 
    { 
     // ... 
     throw null; // The NullReferenceException will get caught below 
     // ... 
    } 
    catch (Exception ex) 
    { 
     _ThreadException = ex; 
    } 
} 

Jeśli jest to aplikacja UI, rzeczy są nieco łatwiejsze. Będziesz musiał podać jakieś odwołanie do swojego wątku UI w metodzie Go, aby wiedział, gdzie wysłać wyjątek. Najlepszym sposobem na to jest przekazanie SynchronizationContext wątku interfejsu użytkownika.

Coś jak to będzie działać:

public static void Main() 
{ 
    var ui = SynchronizationContext.Current; 
    new Thread (() => Go(ui)).Start(); 
} 

static void HandleException(Exception ex) 
{ 
    // this will be run on the UI thread 
} 

static void Go(SynchronizationContext ui) 
{ 
    try 
    { 
     // ... 
     throw null; // The NullReferenceException will get caught below 
     // ... 
    } 
    catch (Exception ex) 
    { 
     ui.Send(state => HandleException(ex), null); 
    } 
} 
0

Zakładam, że twój tak zwany "główny wątek" powinien sondować lub czekać na wyjątki. Można to zrobić za pomocą kolejki i semafora.

catch(Exception ex) 
{ 
    lock(queueLock) 
    { 
     queue.Enqueue(ex) 
     semaphore.Release(); 
    } 

} 

W głównym wątku możesz sondować lub czekać na semafor.

2

To jest naprawdę stary wątek, ale mam oryginalne podejście do tego problemu, więc przedstawię tutaj moje rozwiązanie.

Głównym celem w moim przypadku było to, że wątek główny zostanie przerwany przez wyjątek w momencie, w którym wątek potomny ma wyjątek, zamiast monitorowania lub czekania, jak proponowano w innych odpowiedziach. Jak już powiedziano w innych wątkach, nie możemy tego zrobić w konwencjonalny sposób, ale możemy wysłać przerwanie z drugiego wątku do głównego wątku.

Wysłanie przerwania na główny wątek generuje wyjątek ThreadInterruptedException na wątku głównym. Przechwycenie go w głównym wątku i sprawdzenie flagi podnoszonej przez inny wątek spowoduje również przeniesienie szczegółów wyjątku.

Oto przykład minimalny (można podzielić go na zajęcia i robić lepsze projektowanie później)

static void Main(string[] args) 
    { 


     // initialize the second thread *************************** 
     Exception exFromThread = null; 

     Thread thread = new Thread((mainThread) => 
     { 
      Thread.Sleep(1000); 
      exFromThread = new Exception("Exception from other thread"); 
      ((Thread)mainThread).Interrupt(); // makes the main thread get exception 
     }); 

     thread.Start(Thread.CurrentThread); 
     // ******************************************************** 

     try 
     { 
      // This loop represents your main thread logic 
      for (int i = 0; true; i++) 
      { 
       Thread.Sleep(500); 
       Console.WriteLine("main thread logic: " + i); 
      } 
     } 
     catch (ThreadInterruptedException ex) 
     { 
      Console.WriteLine("Thread have been interrupted"); 
      Console.WriteLine(exFromThread.Message); 
     } 

     Console.WriteLine("Press any key.."); 

     Console.ReadLine(); 
    } 
Powiązane problemy