确保多个IDisposables顺序处置 [英] Ensuring sequential disposing of multiple IDisposables

查看:183
本文介绍了确保多个IDisposables顺序处置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个 IDisposables ,我需要有处理顺序。顺序是重要的,因为第一个的IDisposable 杀死是依靠将由第二杀死一个服务的接收订阅的IDisposable 。这是在Windows窗体应用程序,其中的IObservable 认购需要在不同的线程,但在观察和处理需求发生在UI线程上发生。 (其实,我不若处置UI线程上发生的,只要为了保证在意。)所以,在代码中,我大致有以下几种(一次降低):

I have two IDisposables that I need to have disposed in sequential order. The ordering is important since the first IDisposable kills an Rx subscription that is relying on a service that will be killed by the second IDisposable. This is within a Windows Forms application where the subscription of the IObservable needs to happen on a different thread but the observing and disposing needs to happen on the UI thread. (Actually, I don't care if the disposing happens on the UI thread as long as the order is ensured.) So, in code I have roughly the following (once reduced):

SomeService = new DisposableService();
Subscription = Foo(someService).SubscribeOn(NewThreadScheduler.Default).ObserveOn(theForm).Subscribe(...)

在一些我需要在顺序(订阅然后SomeService)处理这两种的UI事件。要做到这一点,我已经尝试使用接收的除 CompositeDisposable ContextDisposable 来提供相同的线程上的串行处置:

On a number of UI events I need to dispose of both of these in order (Subscription and then SomeService). To do this I have tried using Rx's CompositeDisposable in addition to the ContextDisposable to provide serial disposing on the same thread:

_Disposable = new CompositeDisposable(new[] {                     
    new ContextDisposable(WindowsFormsSynchronizationContext.Current, Subscription),                     
    new ContextDisposable(WindowsFormsSynchronizationContext.Current, SomeService)});



以上不工作,但是。根据我的记录 _Disposable ContextDisposable SomeService 是所谓同一个线程,但是,从 ContextDisposable 上的服务不同的线程concurent仍然发生被布置(从而导致比赛条件与NPE)。

The above does not work however. Based on my logging _Disposable and the ContextDisposable for SomeService are called on the same thread but the ContextDisposable is still occurring on a different thread concurent with the service being disposed (and thus resulting in race conditions and NPEs).

我只编写C#进行了几个星期,所以我敢肯定,这个问题是我的背景和调度员是如何工作的误解。什么是正确的方法解决这个问题?

I've only been programming C# for a couple of weeks and so I'm sure the problem is my misunderstanding of how contexts and dispatchers work. What is the correct approach to this problem?

推荐答案

SubscribeOn 调度呼吁双方订阅的Dispose 。因此,调用的Dispose 您的订阅的变量,不管执行当前是否在UI线程上与否,在申购结果被调度处置通过 NewThreadScheduler.Default

SubscribeOn schedules the calls to both Subscribe and Dispose. Therefore, calling Dispose on your Subscription variable, regardless of whether execution is currently on the UI thread or not, results in the subscription being scheduled for disposal by NewThreadScheduler.Default.

这是几乎从来没有一个好主意,用 SubscribeOn ;然而,你的情况你声称它解决您的问题的50% - 这比我见过的最用途多50% - 所以我必须问你是否真的需要订阅的后台线程执行中首位。这是创建一个全新的线程,然后就可以调用一个方法非常昂贵,相比之下,只调用UI线程上的方法直接,如果所有的方法确实是开始一些异步工作,如发送网络请求或读取文件。也许,如果计算发送网络消息被证明是过于耗时,然后用 SubscribeOn 可能是正确的;虽然,当然,前提是你要处置计划也是如此。

It's almost never a good idea to use SubscribeOn; however, in your case you're claiming that it solves 50% of your problem - and that's 50% more than most uses I've seen - so I must question whether or not you actually need the subscription to execute on a background thread in the first place. It's awfully expensive to create a brand new thread and then invoke a method on it, compared to just calling a method on the UI thread directly, if all the method does is begin some asynchronous work such as sending a network request or reading a file. Perhaps if computing a network message to be sent is proven to be overly time-consuming, then using SubscribeOn may be correct; although, of course, only if you want disposal scheduled as well.

如果订阅您观​​察到的,必须在后台线程执行,但处理必须保持自由线程,然后再考虑用下面的操盘手(未经测试)。

If the subscription to your observable must execute on a background thread, yet disposal must remain free-threaded, then consider using the following operator instead (untested).

public static class ObservableExtensions
{
  public static IObservable<TSource> SubscribeOn<TSource>(
    this IObservable<TSource> source,
    bool doNotScheduleDisposal, 
    IScheduler scheduler)
  {
    if (!doNotScheduleDisposal)
    {
      return source.SubscribeOn(scheduler);
    }

    return Observable.Create<TSource>(observer =>
      {
        // Implementation is based on that of the native SubscribeOn operator in Rx
        var s = new SingleAssignmentDisposable();
        var d = new SerialDisposable();
        d.Disposable = s;
        s.Disposable = scheduler.Schedule(() =>
        {
          d.Disposable = source.SubscribeSafe(observer);
        });
        return d;
      });
  }
}

这篇关于确保多个IDisposables顺序处置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆