且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

线程中止异常in.NET 4.5

更新时间:2023-12-05 10:05:46


  

是什么原因导致ThreadAbortException?


块引用>

请参阅 ThreadAbortException :当呼叫来中止方法中时引发的异常。避免使用所有手动相关code在 DoAfter 方法。


  

请问有什么方法可以让周围的ThreadAbortException?


块引用>

是的......利用异步等待关键字正确遵循***的编程实践和模式。

下面是我建议的修改:

  [HTTPGET]
公共异步任务<串GT; TestThreadAbortException()
{
    InitToolkit(); //初始化记录仪,DB等。    VAR的结果=等待DoAfter(5.Seconds(),MyAction);    返回结果;
}

标记您的控制器方法任务< T> 回国,其中 T 是返回类型。在这种情况下,字符串

如果您需要简单地启动后台测井作业,然后返回到客户端,你应该考虑的QueueBackgroundWorkItem$c$c>.而不是使用 Thread.sleep代码使用 Task.Delay ,方法标记为工作任务< T> 是异步操作的再presentative

 公共异步任务< T> DoAfter< T>(时间跨度WAITFOR,Func键<记录器,任务< T>>动作)
{
    等待Task.Delay(WAITFOR);
    DatabaseLogger记录器=新DatabaseLogger();
    logger.Log(执行+ action.Method.Name +,+ DateTime.Now.ToLongTimeString());
    尝试
    {
        返回等待操作(记录);
        logger.Log(成功执行+ action.Method.Name +,+ DateTime.Now.ToLongTimeString());
    }
    赶上(例外五)
    {
        logger.Log(错误+ action.Method.Name +:+ e.Message +,+ DateTime.Now.ToLongTimeString());
    }
    最后
    {
        logger.CloseDatabase();
    }
}私人异步任务MyAction(记录器记录器)
{
    VAR的结果=等待的MyMethod();
    logger.Log(结果);
}私人异步任务<串GT;的MyMethod()
{
    等待Task.Delay(20000);
    返回测试;
}

From IIS, when I am calling some background task in a new thread, it only runs through if the task does not contain certain asynchronous calls.

If I call a background task in a new thread, that does contain these asynchronous calls, it does return a ThreadAbortException, while the same Action, being executed synchronously inside ApiController, does run through, and a different action, called asynchronously, also runs through.

Furthermore, when I call one action synchronously as well as the other action asynchronously, the asynchronous call fails as well.

  • What does cause the ThreadAbortException?
  • Is there anything I can do to get around the ThreadAbortException?

Code:

[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
    {
    }
}

Background information: In the production code, the inner async call, where during debugging I just create a new task, is created inside a Microsoft library that does not offer synchronous methods, so I won't be able to just "remove the Task".

What causes the ThreadAbortException?

See ThreadAbortException: "The exception that is thrown when a call is made to the Abort method". Avoid using all the manual Thread related code in the DoAfter method.

Is there anything I can do to get around the ThreadAbortException?

Yes... utilize the async and await keywords correctly following best programming practices and patterns.

Here are my suggested modifications:

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

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

    return result;
}

Mark your controller method as Task<T> returning, where T is the type to return. In this case a string.

If you need to simply start a background logging job and then return to the client, you should consider QueueBackgroundWorkItem. Instead of using Thread.Sleep use Task.Delay, mark methods as Task or Task<T> that are representative of asynchronous operations.

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";
}