2012-01-08 2 views
8

Я знаком с тем, что исключение, брошенное в поток, обычно не могло быть обнаружено в другом потоке. Как перенести ошибку, однако, в основной поток?Как передать исключение явно в основной поток в 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 
    // ... 
    } 
} 

ответ

6

Если вы используете .NET 4 Есть лучшие способы сделать это с Tasks, но при условии, что вам нужно использовать Threads ...

Если ваш пример консольного приложения, то ваш главный метод выхода , возможно, до запуска Go. Таким образом, ваш «основной поток» может не существовать, когда генерируется исключение. Чтобы остановить это, вам нужна некоторая синхронизация.

Что-то вроде этого нужно сделать:

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

Если это приложение пользовательского интерфейса, все немного проще. Вам нужно будет передать некоторую ссылку на ваш поток пользовательского интерфейса в метод Go, чтобы он знал, куда отправить исключение. Лучший способ сделать это - передать SynchronizationContext потока пользовательского интерфейса.

Что-то, как это будет работать:

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

Если C# 4.0 доступен для вас, то вы можете использовать Task вместо Thread. Необлученные исключения в Task автоматически распространяются на соединительный поток. См. Здесь: http://msdn.microsoft.com/en-us/library/dd997415.aspx для примеров и исключений из этого правила.

+0

C# 4.0 не доступен – user829174

0

Я предполагаю, что ваш так называемый «основной поток» должен опросить или ждать исключений. Это можно сделать с помощью очереди и семафора.

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

} 

В вашей основной теме вы можете опросить или дождаться семафора.

2

Это действительно старая тема, но у меня есть оригинальный подход к этой проблеме, поэтому я поставлю свое решение здесь.

Основная цель в моем случае состояла в том, что основной поток будет прерван исключением на тот момент, когда дочерний поток получил исключение, вместо того, чтобы отслеживать или ждать, как предложено в других ответах. Как было сказано в других потоках, мы не можем сделать это обычным способом, но мы можем отправить прерывание из другого потока в основной поток.

Отправка прерывания в основной поток генерирует ThreadInterruptedException в основном потоке. Таким образом, поймав его в основном потоке и проверив любой флаг, поднятый другим потоком, будет также передаваться информация о деталях исключений.

Вот минимальный пример (вы можете разбить его на классы и делать лучше дизайн позже)

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(); 
    } 
Смежные вопросы