取消运行任务从ThreadPool.QueueUserWorkItem开始

时间:2013-05-07 13:24:14

标签: .net multithreading threadpool

我们有一个通过ThreadPool.QueueUserWorkItem命令启动长时间运行任务的进程。

里面的每个任务,通过AppDomain.CreateDomain调用加载一个新的AppDomain,处理一堆东西并退出。有时,这些应用程序内部的处理时间过长,如果运行时间太长,则需要中止。

我想了解是否有可能在他们不知情的情况下从外部中止这些线程,以便正确卸载他们的AppDomain?

正如您在下面的代码中所看到的,当前appdomain是作为局部变量创建的,但如果需要,它可以移动到类成员。我杀死该线程的最佳方法是卸载该appdomain,就像整个try / catch的“finally”子句中所做的那样。但是,我不确定我是否能够“从外部”访问它(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);
        }
}

1 个答案:

答案 0 :(得分:0)

一个基本点,如果我正在教我如何吸蛋,可以提前道歉。提交给线程池的任务不一定立即运行。他们等到池中的一个线程空闲然后启动。

因此,如果在调用QueueUserWorkItem时已经运行了一些线程池任务,则新任务必须等待。您可以通过在调用QueueUserWorkItem()时记录是否是这种情况,并在达到try块的第一行时再次记录。这两个日志条目之间的巨大时差背叛了原因。

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

中止被阻止的事情很难用很多语言干净地完成。你真的必须这样做的唯一原因是因为你正在使用一个线程池线程。但是,如果它是一个合适的线程,那么如果任务需要很长时间,则无关紧要。假设延迟是等待域控制器响应线程,则最有可能陷入被阻塞的套接字读取。如果是这样的话,它不会占用任何处理器时间,并且让它自然地完成或放弃它自然需要多长时间并没有多大的伤害。