如何在c#中完全静默地终止一个任务



我的代码看起来像这样:

private void DoWork() {
try
{
MakeCallToServiceWhichCreatesResource();
UpdateState()
}
catch (Exception e)
{
UpdateState()
}
}

然而,有一个问题,当我们的服务有一个部署,它立即杀死线程,没有异常。因此,线程在调用服务的过程中被终止,这产生了一个问题,因为服务调用生成的资源在状态中没有更新,因此变得悬空并且不可恢复。然后,我对以下内容进行了修改:

private void DoWork() {
try
{
UpdateStateWithOutputInAnticipationOfServiceCall()
MakeCallToServiceWhichCreatesResource();
}
catch (Exception e)
{
UpdateStateToRemoveOutput()
}
}

这将解决线程在调用时被杀死的问题,因为资源可以稍后删除(如果外部服务调用失败,进行不必要的删除调用是可以接受的)。但是,我现在希望为这个场景添加一个单元测试,但是我不确定如何模拟完全线程删除。使用线程中止似乎不起作用,因为它会抛出一个异常,而不是立即杀死,但环境failfast似乎不起作用,因为据我所知,它会杀死单元测试环境。任何关于如何建立一个单元测试,可以核线程运行代码的想法?

关于如何中止线程,是无声地还是大声地,您可以看看这个问题。剧透警告,在最新的。net平台中这两种都不可能。如果你为此感到悲伤,那么了解Thread.Abort的死亡是确定的和不可逆转的,你可能会感觉好一些:

用于生产场景的Thread.Abort不会回到。net Core。对不起。

关于如何改进你的代码,我建议你熟悉finally关键字。它在简化和强化资源处置方面有很大帮助:

private void DoWork()
{
try
{
MakeCallToServiceWhichCreatesResource();
}
finally
{
UpdateState();
}
}

关于如何防止线程静默死亡,一个想法是避免抑制catch块中的错误。throw是你的朋友:

private void DoWork()
{
try
{
MakeCallToServiceWhichCreatesResource();
UpdateState();
}
catch (Exception ex)
{
UpdateState();
throw;
}
}

现在你的线程会大声死去,把进程也带走。这可能不是你想要的。

在尖叫和痛苦中死去和在完全沉默中死去之间找到平衡的一种方法是使用任务而不是线程。您可以使用Task.Run方法将DoWork调用卸载到ThreadPool,并且您将返回一个表示执行结果的Task对象。您可以将此任务存储在一个字段或任务列表中,并定期检查其属性,如Status,IsCompleted,IsFaulted,Exception等,以了解如何做。您还可以为它附加延续(ContinueWith),以便记录其完成情况或其他内容。如果您熟悉asyncawait,也可以使用await。最好的部分是,如果您的任务失败了,运行它的线程不会随之死亡。该线程将返回ThreadPool,并可用于未来的Task.Runs或其他工作。
Task workTask = Task.Run(() => DoWork());