32U*_*32U 7 c# multithreading task
我有一个在应用程序域中运行的控制台应用程序.应用程序域由自定义Windows服务启动.该应用程序使用父任务来启动多个有效的子任务.当计时器查找新工作时,可以有许多子任务在任何给定时间运行子项.
所有父任务的句柄位于任务列表中:
static List<Task> _Tasks = new List<Task>();
Run Code Online (Sandbox Code Playgroud)
当管理员更改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);
Run Code Online (Sandbox Code Playgroud)
自定义GAC dll包含一个完成工作的类.GAC功能中没有共享对象.GAC类在每个子任务中实例化:
Export export = new Export();
Run Code Online (Sandbox Code Playgroud)
每个子任务在执行期间的某个时刻调用方法:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
searchResultList任务之间不共享.应用程序运行时,export.Execute将按预期执行所有子任务.当在应用程序中检测到停止信号时,它会尝试等待所有子任务结束.我已经尝试了几种方法来等待每个父项下的子任务结束:
foreach (var task in _Tasks){task.Wait();}
Run Code Online (Sandbox Code Playgroud)
和
while (_Tasks.Count(t => t.IsCompleted) != _Tasks.Count){}
Run Code Online (Sandbox Code Playgroud)
等待代码执行时会发生线程异常:
Error in Export.Execute() method: System.Threading.ThreadAbortException: Thead was being aborted at WFT.CommonExport.Export.Execute(ICollection '1 searchResults)
Run Code Online (Sandbox Code Playgroud)
我不希望使用取消令牌,因为我希望任务完成,而不是取消.
我不清楚为什么GAC类方法不满意,因为每个任务都应该有一个方法对象的唯一句柄.
更新:
感谢您的评论.只是为了进一步澄清这里发生的事情......
从理论上讲,等待儿童任务的方法应该没有任何理由:
while (_Tasks.Count(t => t.IsCompleted) != _Tasks.Count){}
Run Code Online (Sandbox Code Playgroud)
但是不应该工作
Task.WaitAll()
Run Code Online (Sandbox Code Playgroud)
肯定是一个更好的方法,并帮助充实问题.在进一步测试之后,事实证明其中一个问题是,当app域应用程序告诉调用服务时,没有通过填充服务读取的插槽来完成工作:
AppDomain.CurrentDomain.SetData("Status", "Not Exporting");
Run Code Online (Sandbox Code Playgroud)
该语句在代码中的时间和位置在应用程序中是错误的.作为多线程的新手,我花了一段时间才发现当我发布SetData"Not Exporting" 时任务仍在运行.因此,当服务认为可以关闭并删除应用程序域时,我认为这导致了ThreadAbortException.我已经将SetData声明移到了一个更可靠的位置.
回答您的问题:您正在接收线程中止,因为任务是在“后台”线程上执行的。
在应用程序终止之前,不会等待后台线程。请参阅此MSDN链接 以获取更多说明。
现在尝试帮助解决您的实际问题,我建议使用Task.WaitAll()Jim提到的方法,但是您应该更可靠地处理应用程序终止。我怀疑当您在关闭之前等待任务完成时,不会阻止新任务入队。
我建议使用退出阻止信号量,并且使任务入队的系统在初始化时将其递增,而在处置时将其递减。