.net 取消运行以ThreadPool.QueueUserWorkItem启动的任务

.net 取消运行以ThreadPool.QueueUserWorkItem启动的任务,.net,multithreading,threadpool,.net,Multithreading,Threadpool,我们有一个进程,它通过ThreadPool.QueueUserWorkItem命令启动长时间运行的任务 内部的每个任务,通过AppDomain.CreateDomain调用加载一个新的AppDomain,处理一堆内容并退出。有时,这些应用程序内部的处理时间太长,如果运行时间太长,则需要中止 我想了解是否有可能在不知情的情况下从外部中止这些线程,以便正确卸载它们的AppDomain 正如您在下面的代码中所看到的,当前appdomain是作为局部变量创建的,但如果需要,可以将其上移到类成员。对我来说

我们有一个进程,它通过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);
        }
}
public void异步执行(RunningState RunningState)
{
RunningState returnedState=null;
AppDomain runningApp=null;
尝试
{
{
var ads=新的AppDomainSetup
{
ApplicationBase=AppDomain.CurrentDomain.BaseDirectory,
DisallowBindingRedirects=false,
DisallowCodeDownload=false,
ConfigurationFile=AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
};
runningApp=AppDomain.CreateDomain(“RemoteMonitor_389;”+runningState.LocalAccountInfo.Id,null,
广告);
变量子=
runningApp.CreateInstanceAndUnwrap(“Processor”、“Processor.ProcessorSub”)
作为ProcessorSub;
如果(sub!=null)
{
returnedState=sub.Run(runningState);
}
其他的
Logger.Instance.WriteCritical(“无法创建处理器对象”);
}
}
捕获(例外情况除外)
{
Logger.Instance.WriteError(例如Message,ex);
}
最后
{
如果(runningApp!=null)
卸载(runningApp);
if(_onCompleteHandler==null)
Logger.Instance.WriteCritical(“无法完成任务”);
其他的
_调用(returnedState);
}
}

一个基本点,如果我在教如何吮吸卵子,我会提前道歉。提交到线程池的任务不一定会立即运行。它们等待池中的一个线程空闲,然后启动

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

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


在许多语言中,很难干净地中止被阻止的事情。你不得不这么做的唯一原因,实际上,是因为你在使用一个线程池线程。然而,如果它是一个合适的线程,那么如果任务需要花费很长时间,这一点都不重要。假设延迟下降到等待域控制器响应,线程很可能被阻塞的套接字读取卡住。如果是这样的话,它不会占用任何处理器时间,让它挂起自然需要多长时间才能完成或自行放弃也没有多大害处。

调用
Run
后,您有没有办法中止
对象?否。但是,我可以调用这个:AppDomain.Unload(runningApp)来卸载整个AppDomain对象。这是我的首选,它容易丢失数据,并可能使锁处于打开状态…理解,但不担心锁或数据丢失。只是不确定如何从线程的“外部”调用该方法。您必须有某种方式与appdomain通信(通过由mashalbyref基础自动处理的远程处理),以便中止使用
QueueUserWorkItem
创建的任何跟踪线程(是的,您也必须跟踪它们)。否则,您实际上只能卸载appdomain。如果只是卸载appdomain还不能完全正常工作,那么你可能就不走运了。为什么不将
中止
方法添加到
Processor.ProcessorSub