Отправка исключения из потока в основной поток? - PullRequest
14 голосов
/ 04 августа 2010

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

Ответы [ 6 ]

13 голосов
/ 04 августа 2010

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

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

4 голосов
/ 17 августа 2010

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

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;
}
3 голосов
/ 04 августа 2010

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

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

2 голосов
/ 05 августа 2010

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

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

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

Редактировать:

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();
2 голосов
/ 04 августа 2010

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

2 голосов
/ 04 августа 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...