2013-05-07 112 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块的第一行到达时再次判断是否如此。这两个日志条目之间的大的时间差异背离了原因。

您可以增加线程池中的线程数。

中止被阻塞的东西很难在很多语言中清理干净。你真的必须这样做的唯一原因是因为你正在使用线程池线程。但是,如果它是一个合适的线程,而不是一个记录,如果任务需要时间。假设延迟等待域控制器响应,则线程最可能被卡在被阻塞的套接字读取中。如果是这样的话,它不会消耗任何处理器时间,并且没有太多的伤害,因为它永远需要花费很长时间才能自行完成或放弃。