2013-05-07 121 views
0

我們有一個通過ThreadPool.QueueUserWorkItem命令啓動長時間運行任務的進程。取消正在使用ThreadPool.QueueUserWorkItem啓動的運行任務

裏面的每個任務,通過AppDomain.CreateDomain調用加載一個新的AppDomain,處理一堆東西並退出。有時,這些應用程序內部的處理時間過長,如果運行時間過長,則需要中止處理。

我想了解是否可以在不知情的情況下從外部中止這些線程,以便AppDomains正確卸載?

正如您在下面的代碼中看到的那樣,目前appdomain被創建爲局部變量,但如果需要它可以移動到類成員。我殺死線程的最好方法是在整個try/catch的「finally」子句中卸載該appdomain。但是,我不確定是否能夠從外部訪問它(appdomain),因爲AsyncExecute在不同於中止調用者的線程上運行。

這裏是啓動任務的處理功能:

public void AsyncExecute(RunningState runningState) 
{ 
    RunningState returnedState = null; 
     AppDomain runningApp = null; 

     try 
     { 
      { 

       var ads = new AppDomainSetup 
           { 
            ApplicationBase = AppDomain.CurrentDomain.BaseDirectory, 
            DisallowBindingRedirects = false, 
            DisallowCodeDownload = false, 
            ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile 
           }; 
       runningApp = AppDomain.CreateDomain("RemoteMonitor_" + runningState.LocalAccountInfo.Id, null, 
                ads); 
       var sub = 
        runningApp.CreateInstanceAndUnwrap("Processor", "Processor.ProcessorSub") 
        as ProcessorSub; 
       if (sub != null) 
       { 
        returnedState = sub.Run(runningState); 
       } 
       else 
        Logger.Instance.WriteCritical<ExecutableItem>("Cannot create Processor object"); 
      } 
     } 
     catch (Exception ex) 
     { 
      Logger.Instance.WriteError<ExecutableItem>(      ex.Message, ex); 
     } 
     finally 
     { 
      if (runningApp != null) 
       AppDomain.Unload(runningApp); 

      if (_onCompleteHandler == null) 
       Logger.Instance.WriteCritical<ExecutableItem>("Cannot complete task"); 
      else 
       _onCompleteHandler.Invoke(returnedState); 
     } 
} 
+0

在調用Run之後,您是否有辦法中止'sub'對象? – 2013-05-07 14:37:57

+0

否定的。我可以調用這個:AppDomain.Unload(runningApp)來卸載整個appdomain對象。哪一個是我的首選 – Igorek 2013-05-07 14:45:18

+0

這很容易造成數據丟失並可能使鎖打開...... – 2013-05-07 14:49:42

回答

0

一個基本點,許多道歉提前如果我教怎麼班門弄斧。提交給線程池的任務不一定會立即運行。他們一直等到游泳池中的其中一個線程空閒,然後纔開始。

因此,如果在調用QueueUserWorkItem時已經有幾個線程池任務正在運行,那麼您的新任務必須等待。您可以通過在調用QueueUserWorkItem()時進行日誌記錄,並在try塊的第一行到達時再次判斷是否如此。這兩個日誌條目之間的大的時間差異背離了原因。

您可以增加線程池中的線程數。

中止被阻塞的東西很難在很多語言中清理乾淨。你真的必須這樣做的唯一原因是因爲你正在使用線程池線程。但是,如果它是一個合適的線程,而不是一個記錄,如果任務需要時間。假設延遲等待域控制器響應,則線程最可能被卡在被阻塞的套接字讀取中。如果是這樣的話,它不會消耗任何處理器時間,並且沒有太多的傷害,因爲它永遠需要花費很長時間才能自行完成或放棄。