繁体   English   中英

使用任务发生意外的线程中止异常。 为什么?

[英]Unexpected Thread Abort Exception using Tasks. Why?

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

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

 static List<Task> _Tasks = new List<Task>();

当管理员更改xml配置文件时(或当呼叫服务关闭时),Windows服务可以通过在应用程序域槽中放置字符串令牌来向正在运行的应用程序发送停止信号。 应用程序在计时器上运行并检查要在插槽中关闭的信号,然后尝试通过等待所有任务结束来优雅地结束它正在执行的操作。

任务开始如下:

Task parent = Task.Factory.StartNew(() =>
            {
                foreach (var invoiceList in exportBucket)
                {
                    KeyValuePair<string, List<InvoiceInfo>> invoices = new KeyValuePair<string, List<InvoiceInfo>>();
                    invoices = invoiceList;
                    string taskName = invoices.Key; //file name of input file
                    Task<bool> task = Task.Factory.StartNew<bool>(state => ExportDriver(invoices),
                        taskName, TaskCreationOptions.AttachedToParent);
                }
            });
            _Tasks.Add(parent);

自定义GAC dll包含一个完成工作的类。 GAC功能中没有共享对象。 GAC类在每个子任务中实例化:

Export export = new Export();

每个子任务在执行期间的某个时刻调用方法:

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();}

while (_Tasks.Count(t => t.IsCompleted) != _Tasks.Count){}

等待代码执行时会发生线程异常:

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()

肯定是一个更好的方法,并帮助充实问题。 经过进一步测试后发现其中一个问题是,当app域应用程序告诉调用服务时,没有通过填充服务读取的插槽来完成工作:

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

该语句在代码中的时间和位置在应用程序中是错误的。 作为多线程的新手,当我将SetData发布为“Not Exporting”时,我花了一段时间才弄清楚任务仍在运行。 因此,当服务认为可以关闭并删除应用程序域时,我认为这会导致ThreadAbortException 我已经将SetData语句移动到更可靠的位置。

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

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

现在尝试帮助解决您的实际问题,我建议Jim提到的Task.WaitAll()方法,但是您应该更强大地处理应用程序终止。 我怀疑在关闭之前等待任务完成时,您不会阻止新任务入队。

我建议使用一个出口阻塞信号量和enques任务的系统在初始化时递增它,并在dispose上递减。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM