2010-08-04 6 views
14

Я хочу передать исключение из текущего потока (этот поток не является основным потоком) в основной поток. Почему? Поскольку я проверяю свою жесткую блокировку в другом потоке (этот поток использует таймер для проверки), а когда HardLock недоступен или недействителен, я создаю исключение, которое определяется мной, а затем выкидывает это исключение.
Чтобы исключение не срабатывало. ; (Отправка исключения из потока в основной поток?

+0

я могу использовать 'публичный статический method' в Program.cs и вызвать его из другого потока (Потому что это статический класс), и прекратить применение с' application.exit', но это хорошо только для завершения приложения ' НЕ делайте никаких других действий! – Rev

ответ

13

Ваш лучший выбор - заменить Thread на Task (новый в .NET 4.0). Класс Task обрабатывает правильное маршалинг исключения, независимо от того, какой поток проверяет результат задачи.

Если использование .NET 4.0 невозможно, то CoreEx.dll из Rx extensions включает в себя метод расширения Exception.PrepareForRethrow, который сохраняет стек вызовов для исключений. Вы можете использовать это в сочетании с предложением MaLio о SynchronizationContext для исключения исключения из другого потока.

3

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

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

+0

так как это вы говорите! любой образец – Rev

+0

хороший сайт, описывающий потоки и связывающий между собой http://www.albahari.com/threading/ – Patrick

2

Передайте ссылку на контекст выполнения основной формы на t он нить (через делегата или поле). Затем вызовите метод (отправить или отправить) через этот контекст синхронизации из потока, который выдает исключение. Контекст выполнения гарантирует, что он обрабатывается нитью ui.

2

Возможно, вам будет легче сохранить обработку исключений в потоке и передать сообщение об исключении и трассировку стека, возвращая MyException.ToString() в обратном вызове. Когда я получаю исключения из другого потока, все, что я ищу, находится в этой строке.

2

Только мои 2 цента.

Я думаю, вы можете использовать Invoke, BeginInvoke в основной форме, если вы используете Windows Forms для отправки исключения из блока try/catch. Или вы можете создать обработчик/делегат события в основном потоке и отправить исключения через него в основной поток, чтобы метод в основном потоке мог его обработать. Честно говоря, не пробовали эти решения, но это мои первые идеи.

PS. Возможно, создание WorkerQueue в основном потоке также является опцией. Он будет работать как backgroundWorker, и когда он получит новое отправленное исключение, он обработает его соответственно ... Я могу дать вам небольшие примеры, если вы заинтересованы.

Edit:

public class JobQueue 
{ 
    private Queue<Exception> pendingJobs = new Queue<Exception>(); 
    private Exception defaultJob = null; 

    bool run = true; 

    public void AddJob(Exception job) 
    { 
     pendingJobs.Enqueue(job); 
    } 

    public JobQueue() 
    { 
     defaultJob=null; 
    } 

    public void StopJobQueue() 
    { 
     run = false; 
    } 


    public void Run() 
    { 
     while (run) 
     { 

       Exception job = (pendingJobs.Count > 0) ? pendingJobs.Dequeue() : defaultJob; 

       if (job!= null) 
       { 
        ////what to do with current Exception 
       } 

      Thread.Sleep(20); //I know this is bad... 
     } 


     pendingJobs.Clear(); 
    } 



} 
} 

Чтобы использовать его: В вашей основной класс резьбы:

private JobQueue m_jobQueue; 

В Initialize() или там, где ваши главные старты резьбы:

Backgroundworker bw = new Backgroundworker(); 
    bw.DoWork+= jobQueue.Run; 
    bw.StartAsync(); 
    //m_jobQueue = new JobQueue(); 
    // new Thread(new ThreadStart(jobQueue.Run)).Start(); 

И для отправки исключения:

m_jobQueue.AddJob(StackOverflowException); 

Остановка по:

m_jobQueue.StopJobQueue(); 
+0

Вы никогда не назначаете 'defaultJob' (или я что-то не хватает?), Для чего он нужен? Простой заменой 'Thread.Sleep' является использование AutoResetEvent (даже работает на Windows Mobile). Создайте новый 'AutoResetEvent', сделайте' while (pendingJobs.Count> 0) {job = pendingJobs.Dequeue(); } ', в случае, если новое задание попадает в очередь в процессе выделения, внутри вашего другого и кладет' resetEvent.WaitOne' вместо Thread.Sleep. В 'Enqueue' вы можете сделать' resetEvent.Set() ', чтобы разбудить его в' Run() '. – Patrick

+0

Привет, Патрик! Ты прав. Я просто в основном скопировал его из моего проекта, удалив большую часть кода для простоты. Виноват. Но, по крайней мере, в качестве примера я думаю, что это будет сделано. Спасибо, что указали эти моменты. – nomail

4

Вы можете использовать исключение в качестве параметра в случае.
И обрабатывайте его после отправки исключения в другой поток.
Пример кода.

public delegate void SendToMainDel(string threadName,Exception ex); 
public event SendToMainDel SendToMainEv; 

public void MySecondThread() 
{ 
    try 
    { 
    .... 
    }catch(Exception ex) 
    { 
     if(SendToMainEv!=null) 
      SendToMainEv("MySecondThread",ex); 
    } 
} 

... 
    SendToMainEv += ReceiveOtherThreadExceptions; 
... 

public void ReceiveOtherThreadExceptions(string threadName,Exception ex) 
{ 
    if(InvokeRequired) 
    { 
     BeginInvoke(new SendToMainDel(ReceiveOtherThreadExceptions), threadName, ex); 
     return; 
    } 

    //there you can handle the exception 
    //throw ex; 
} 
Смежные вопросы