簡體   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