0

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

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

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

正如您在下面的代码中看到的,目前 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);
        }
}
4

1 回答 1

0

一个基本点,如果我在教如何吸鸡蛋,请提前道歉。提交到线程池的任务不一定会立即运行。他们等到池中的线程之一空闲,然后开始。

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

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

在许多语言中,中止被阻止的事情很难干净地完成。实际上,您必须这样做的唯一原因是因为您使用的是线程池线程。但是,如果它是一个适当的线程,那么如果任务花费很长时间,那一点也不重要。假设延迟减少到等待域控制器响应,线程很可能卡在阻塞的套接字读取中。如果是这样,它不会消耗任何处理器时间,并且让它在它自己完成或放弃时自然需要多长时间并没有太大的危害。

于 2013-05-07T23:44:05.287 回答