Отправка исключения из потока в основной поток?

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

Ответы

Ответ 1

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

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

Ответ 2

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

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

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

Только мои 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();