STA 线程异常传播

问题描述 投票:0回答:4

我有一个必须作为 STA 运行的函数,并且我想将其异常传播到调用线程。这是:

public void ExceptionBePropagatedThroughHere()
{
  Thread thread = new Thread(TheSTAThread);
  thread.SetApartmentState(ApartmentState.STA);
  thread.Start();
  thread.Join();
}

public void MainFunction()
{
  try
  {
    ExceptionBePropagatedThroughHere();
  }
  catch(Exception e)
  {
     //will not hit here
  }
}

此处不能选择将 STA 属性放在“MainFunction”上。 我注意到如果我使用任务,尝试捕获任务连接会将异常传播到调用线程,但是我无法指定以 STA 方式运行任务。

问题是如何将作为 STA 运行的异常传播到上例中的“MainFunction”?

提前致谢。

c# multithreading exception
4个回答
4
投票

我遵循了 Hans 的建议,解决方案如下所示,不需要触发任何事件。

private Exception _exception;
public void ExceptionBePropagatedThroughHere()
{
  Thread thread = new Thread(TheSTAThread);Thread thread = new Thread(TheSTAThread);
  thread.SetApartmentState(ApartmentState.STA);
  thread.Start();
  thread.Join();
  if(_exception != null)
    throw new Exception("STA thread failed", _exception);
}

private void TheSTAThread()
{
  try
  {
    //do the stuff
  }
  catch (Exception ex)
  {
    _exception = ex;
  }
}
public void MainFunction()
{
  try
  {
    ExceptionBePropagatedThroughHere();
  }
  catch(Exception e)
  {
     //will not hit here
  }
}

0
投票

在等待期间,您需要保持消息泵的启动和运行。 Thread.Join 不是您可以使用的选项,因为它会阻塞您的线程,直到另一个线程终止。 一个非常简单的消息泵是创建两个名为 StaThreadExited 和 StaThreadExceptionEvent 的事件。您可以对事件数组使用 WaitHandle.WaitAny。如果这是一个异常事件,您可以从例如获取它。共享变量并将其重新抛出到您自己的线程中。我什至前段时间在这里发布了代码

你的, 阿洛伊斯·克劳斯


0
投票

线程是 STA 还是 MTA 并不重要。其中未捕获的异常将使您的应用程序崩溃。您不能将其扔到创建行为不当线程的线程,除非您设计一种手动执行此操作的方法:例如捕获,将其存储在某处,并通知主线程有错误


0
投票

这是一个老问题,但我想我会尝试改进建议的解决方案。 C# 已经具有在线程之间传输异常和结果的便捷机制。这就是所谓的

Task
。如果你需要 STA 线程,你就不能这样做
Task.Run
,但是有了像这样的助手,你可以享受与 STA 线程相同的便利:

public class StaTask {
    public static Task Run(Action action) {
        var tcs = new TaskCompletionSource<object>();
        var thread = new Thread(() => {
            try {
                action();
                tcs.SetResult(null);
            }
            catch (Exception e)
            {
                tcs.SetException(e);
            }
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
        return tcs.Task;
    }
}

当然,可以通过添加通用返回类型来进一步改进。

© www.soinside.com 2019 - 2024. All rights reserved.