任务池线程在初始化性能计数器时阻止UI关闭

时间:2014-02-25 14:45:43

标签: .net wpf system.reactive

我有一个'诊断'服务,它使用Reactive Extensions来观察从几个性能计数器产生的值。它使用Observable.Create将订阅安排到任务池中。

一般来说,这项工作非常好,但有一种情况是PerformanceCounter类的创建会阻止UI进程正确退出并使可执行文件在内存中保持不变(在任务管理器中观察)。

当用户在创建PerformanceCounter实例时关闭应用程序时会发生这种情况 - 这种情况很小。

通常PerformanceCounter实例的创建非常即时,但如果上次没有处理PerformanceCounter的实例,则创建可能需要花费几秒钟的时间,如果用户在此时间窗口内关闭应用程序,该过程将在关闭时挂起。

当应用程序退出时,将调用该服务的dispose方法,因此'一次性'正在关闭Rx流的任何订阅者。

如果阻止尝试创建PerformanceCounter,任何想法如何保证任务池线程都会退出?

下面显示的是构造函数&处置方法:

public DiagnosticsService(IIdleService idleService, IRxSchedulerService rxSchedulerService)
{
    _rxSchedulerService = rxSchedulerService;
    _logger = LogManager.GetCurrentClassLogger();

    _disposable = new CompositeDisposable();
    _bufferedInactiveObservable = Observable.Create<Counters>(x =>
    {
        var disposable = new CompositeDisposable();
        try
        {
            var processName = Process.GetCurrentProcess().ProcessName;

            var workingSetCounter = new PerformanceCounter("Process", "Working Set - Private", processName);
            workingSetCounter.NextValue();
            disposable.Add(workingSetCounter);

            var cpuCounter = new PerformanceCounter("Process", "% Processor Time", processName);
            cpuCounter.NextValue();
            disposable.Add(cpuCounter);

            x.OnNext(new Counters(workingSetCounter, cpuCounter));
        }
        catch (Exception exn)
        {
            x.OnError(exn);
        }

        return disposable;
    })
    .SubscribeOn(rxSchedulerService.TaskPool)
    .ObserveOn(rxSchedulerService.Dispatcher)
    .CombineLatest(idleService.BufferedIdling(IdleBuffer), (x, y) => x)
    .Publish();

    _disposable = _bufferedInactiveObservable.Connect();
}

public void Dispose()
{
    _disposable.Dispose();
}

2 个答案:

答案 0 :(得分:0)

TaskPoolScheduler Rx调度程序子类化,并在您重写方法以在任务上运行操作时,在子类中创建具有TaskCreationOptions.LongRunning标志的任务。在此调度程序上调度的操作将获得将IsBackground属性设置为true的专用线程,从而阻止它们阻止应用程序退出。

答案 1 :(得分:0)

如果您的代码挂在非托管代码中 - 我怀疑这可能就是这种情况 - 在所有任务池线程所在的后台线程上运行可能无助于加速关闭过程。

虽然我不熟悉与阅读性能计数器相关的非托管资源,但我认为它都是非托管内存。所以我相当肯定,在这种情况下,在应用程序关闭的情况下不处理计数器不会导致任何在程序终止后仍然存在的混乱。

虽然感觉有点&#34;脏&#34;但我认为在这种情况下你可以有一个特殊情况,在应用程序关闭时不会处理性能计数器。也许您可以检查一下您设置的静态标志,表明您正在关闭,在这种情况下不能调用Dispose()?关闭时,您可能还需要在性能计数器上调用GC.SuppressFinalize()