C# 使用任务时出现意外的线程中止异常。为什么?

C# 使用任务时出现意外的线程中止异常。为什么?,c#,multithreading,task,C#,Multithreading,Task,我有一个在应用程序域中运行的控制台应用程序。应用程序域由自定义windows服务启动。应用程序使用父任务启动多个子任务。当计时器查找新工作时,可以有许多父任务,子任务在任何给定时间运行 所有父任务的句柄位于任务列表中: static List<Task> _Tasks = new List<Task>(); 每个子任务在执行期间的某个时间点调用一个方法: foreach (var searchResultList in SearchResults) { f

我有一个在应用程序域中运行的控制台应用程序。应用程序域由自定义windows服务启动。应用程序使用父任务启动多个子任务。当计时器查找新工作时,可以有许多父任务,子任务在任何给定时间运行

所有父任务的句柄位于任务列表中:

 static List<Task> _Tasks = new List<Task>();
每个子任务在执行期间的某个时间点调用一个方法:

foreach (var searchResultList in SearchResults)
{
      foreach (var item in searchResultList)
      {
          if (item.Documents.Count > 0)
          {
              //TODO: this is where we get thread issue if telling service to stop
              var exported = export.Execute(searchResultList);
              totalDocuments += exported.ExportedDocuments.Count();
          }
      }
 }
searchResultList
不在任务之间共享。当应用程序运行时,export.Execute按预期对所有子任务执行。当应用程序中检测到停止信号时,它会尝试等待所有子任务结束。我尝试了几种方法来等待每个父项下的子任务结束:

foreach (var task in _Tasks){task.Wait();}

等待代码执行时,出现线程异常:

Error in Export.Execute() method: System.Threading.ThreadAbortException: Thead was being aborted at WFT.CommonExport.Export.Execute(ICollection '1 searchResults)
我不希望使用取消令牌,因为我希望任务完成,而不是取消

我不清楚为什么GAC类方法不满意,因为每个任务都应该有一个唯一的方法对象句柄

更新

谢谢你的评论。只是为了进一步澄清这里发生的事情

从理论上讲,等待子任务的方法不应该有任何理由:

while (_Tasks.Count(t => t.IsCompleted) != _Tasks.Count){}
但这不应该起作用

Task.WaitAll()
这无疑是一个更好的方法,有助于解决问题。进一步测试后发现,其中一个问题是,当应用程序域应用程序告诉调用服务时,填充服务读取的插槽没有完成任何工作:

AppDomain.CurrentDomain.SetData("Status", "Not Exporting");

该语句在代码中的时间和位置在应用程序中是错误的。由于不熟悉多线程,当我将
SetData
改为“不导出”时,我花了一段时间才发现任务仍在运行。因此,当服务认为可以关闭并删除应用程序域时,我认为这导致了
ThreadAbortException
。此后,我将
SetData
语句移到了一个更可靠的位置。

回答您的问题:您正在接收线程中止,因为任务是在“后台”线程上执行的

在应用程序终止之前,不会等待后台线程。有关详细说明,请参阅

现在,为了帮助您解决实际问题,我建议使用Jim提到的
Task.WaitAll()
方法,但是您应该更稳健地处理应用程序终止。我怀疑,当您在关机前等待任务完成时,并没有阻止新任务排队


我建议使用一个出口阻塞信号量,系统允许任务在初始化时增加该信号量,在dispose时减少该信号量。

您不使用
Task.WaitAll(_tasks)
?好主意。我添加了Task[]tasks=\u tasks.ToArray();Task.WaitAll(任务);但不幸的是,当我在任务操作中取消时,我得到了同样的错误。实际上,这确实在一定程度上改变了情况。在任务执行期间取消时,我无法再强制执行异常。但任务的全部工作永远不会完成。虽然我是为这种失败而设计的,但我不得不怀疑任务方法调用第二个方法这一事实是否有任何关系。@Jim在进一步的测试中,我发现WaitAll()现在起作用了,并且我告诉应用程序关闭的时间很微妙。当服务再次启动时,设计需要(并且确实)恢复状态。好提示。谢谢。附件中的选项意味着你不必做任何事情。只需发送停止信号,然后进入退出(在父任务中)。或者,在没有该选项的情况下尝试您当前的代码。谢谢jaysun。事实上,我确实实现了一些类似的东西,而且似乎所有东西都在为手动服务站工作。在某些关机场景中,例如系统重新启动,并且由于这是作为服务运行的,因此您可以做的很少。这更困难,但您仍然可以尝试优雅地处理关机事件:1)钩住与系统关机相关的win32 api 2)实现事务系统。我对我的一个应用程序所做的是将工作缓冲区保存到磁盘,并在成功完成工作后将其从磁盘中删除。因此,如果在处理过程中中止(或崩溃),我可以稍后重试。这意味着有一些小机会执行相同的工作两次,但我的应用程序处理这种情况优雅。无论如何,希望这有帮助:)祝你好运。
while (_Tasks.Count(t => t.IsCompleted) != _Tasks.Count){}
Task.WaitAll()
AppDomain.CurrentDomain.SetData("Status", "Not Exporting");