【问题标题】:Thread Abort Exception in.NET 4.5.NET 4.5 中的线程中止异常
【发布时间】:2016-05-09 13:10:05
【问题描述】:

在 IIS 中,当我在新线程中调用某个后台任务时,它只会在任务不包含某些异步调用时运行。

如果我在包含这些异步调用的新线程中调用后台任务,它会返回一个ThreadAbortException,而在ApiController 中同步执行的相同操作确实会运行,并且会执行不同的操作,异步调用,也贯穿。

此外,当我同步调用一个动作以及异步调用另一个动作时,异步调用也会失败。

  • 是什么导致ThreadAbortException
  • 有什么办法可以绕过ThreadAbortException

代码:

[HttpGet]
public string TestThreadAbortException()
{
    InitToolkit(); // Initialize Logger, DB etc.
    DebugController.DoAfter(5.Seconds(), MyAction); // Runs through!
    //TestThreadAbortException(logger); // Runs through!
    //Combining the first and the second line makes the first one throw the Exception as well.
    //DebugController.DoAfter(10.Seconds(), TestThreadAbortException); // throws Exception
    return String.Join("\r\n",logger.Flush());
}

private void TestThreadAbortException(Logger logger)
{
    Task<string> task = new Task<string>(MyMethod);
    task.Start();
    Task.Run(async () => await task);
    try
    {
        var result = ConfigureAwait(task, false).Result;
    }
    catch (System.AggregateException ex)
    {
        if (ex.InnerExceptions.Count == 1)
        {
            throw ex.InnerExceptions[0];
        }
        throw;
    }
}

private async Task<string> ConfigureAwait(Task<string> task, bool continueOnCapturedContext)
{
    return await task.ConfigureAwait(continueOnCapturedContext: continueOnCapturedContext);
}

private string MyMethod()
{
    Thread.Sleep(20000);
    return "Test";
}

private void MyAction(Logger logger)
{
    logger.Log(MyMethod());
}

public static void DoAfter(TimeSpan waitFor, Action<Logger> action)
{
    try {
        ThreadStart work = () =>
        {
            Thread.Sleep(waitFor);
            DatabaseLogger logger = new DatabaseLogger();
            logger.Log("Executing " + action.Method.Name + ", " + DateTime.Now.ToLongTimeString());
            try
            {
                action.Invoke(logger);
                logger.Log("Successfully executed " + action.Method.Name + ", " + DateTime.Now.ToLongTimeString());
            }
            catch (Exception e)
            {
                logger.Log("Error in " + action.Method.Name + ": " + e.Message + ", " + DateTime.Now.ToLongTimeString());
            }
            logger.CloseDatabase();
        };
        Thread thread = new Thread(work);
        thread.Start();
    }
    catch
    {
    }
}

背景信息:在生产代码中,内部异步调用(在调试期间我只是创建一个新任务)是在不提供同步方法的 Microsoft 库中创建的,因此我将无法仅“删除任务”。

【问题讨论】:

  • 不要将new Threadasync 一起使用!
  • @DavidPine 为什么不呢?请详细说明。
  • 使用asyncawait 会为你处理这个问题......应该不需要手动启动一个新线程,尤其是在网络服务器上。
  • "The async and await keywords don't cause additional threads to be created." 好吧,我想创建一个后台线程,它不应该被前台进程等待,即使在前台进程完成后也应该继续。不完全确定如何做到这一点......
  • 现在构建答案

标签: c# .net multithreading iis asynchronous


【解决方案1】:

是什么导致了 ThreadAbortException?

参见ThreadAbortException:“调用 Abort 方法时引发的异常”。避免在DoAfter方法中使用所有手动的Thread相关代码。

有什么办法可以绕过 ThreadAbortException 吗?

是的...按照最佳编程实践和模式正确使用 asyncawait 关键字。

以下是我建议的修改:

[HttpGet]
public async Task<string> TestThreadAbortException()
{
    InitToolkit(); // Initialize Logger, DB etc.

    var result = await DoAfter(5.Seconds(), MyAction);

    return result;
}

将您的控制器方法标记为Task&lt;T&gt; 返回,其中T 是要返回的类型。在本例中为string

如果您需要简单地启动后台日志记录作业然后返回到客户端,您应该考虑QueueBackgroundWorkItem。不要使用Thread.Sleep,而是使用Task.Delay,将代表异步操作的方法标记为TaskTask&lt;T&gt;

public async Task<T> DoAfter<T>(TimeSpan waitFor, Func<Logger, Task<T>> action)
{
    await Task.Delay(waitFor);
    DatabaseLogger logger = new DatabaseLogger();
    logger.Log("Executing " + action.Method.Name + ", " + DateTime.Now.ToLongTimeString());
    try
    {
        return await action(logger);
        logger.Log("Successfully executed " + action.Method.Name + ", " + DateTime.Now.ToLongTimeString());
    }
    catch (Exception e)
    {
        logger.Log("Error in " + action.Method.Name + ": " + e.Message + ", " + DateTime.Now.ToLongTimeString());
    }
    finally
    {
        logger.CloseDatabase();
    }
}

private async Task MyAction(Logger logger)
{
    var result = await MyMethod();
    logger.Log(result);
}

private async Task<string> MyMethod()
{
    await Task.Delay(20000);
    return "Test";
}

【讨论】:

  • 我认为QueueBackgroundWorkItem 正是我搜索的内容。将为我现在遇到的问题提出一个新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-23
  • 2011-04-15
  • 1970-01-01
  • 1970-01-01
  • 2011-05-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多