1

I'm working in C# WPF with a proprietary framework (essentially a blend of Caliburn Micro and Castle Windsor) and I've got two singleton modules that have a race condition:

DeviceService - A service that manages a connection to a physical device emitting data. The service is "Startable" and hence is automatically constructed and initialized asynchronously.

ConnectionIndicatorViewModel - A client ViewModel that chiefly concerns itself with communicating to the user the status of the connection managed by DeviceService. Changes state mainly based on events fired by DeviceService.

My problem lies at application startup. In the constructor for the ViewModel, I set the default state to "Pending" because I assume that the Service has not finished initializing. Then the ViewModel simply handles the "Initialized" event fired by the Service. It's in this handler that I asses the actual connection state via a property on the Service and update the ViewModel.

Now, all of this works just fine because it is extremely unlikely that the race condition poke its head in. However, in the unlikely case that the Service finishes its initialization before the ViewModel is constructed, it will never handle that "Initialized" event and will just stay in its "Pending" state.

I've considered changing the Service interface to return awaitable types for properties, so that any module trying to access properties will have to wait for initialization to finish, but I'm not sure that this is the best approach. I'm also wary of having part of the client kick off the Service because then who should initialize it if several modules use it?

Is there some conventional way of dealing with this sort of asynchronous initialization that I am missing?

  • When the ViewModel depends on the Service it could check the service's Initialized property whether the service is ready. If ready start fetching. If not the ViewModel will wait until the event is received. – BionicCode Jul 15 '14 at 19:21
  • I've considered that, too, but (if I don't fool around with locks) couldn't that result in nondeterminism? Consider the "Initialized" event firing after the `IsInitialized` property check but before the state is set. That could result in the correct connection state being overwritten by the "Pending" state. – jiminychris Jul 15 '14 at 20:08
  • Hmm. You check IsInitialized to check if the service is already initialized -> if result false => Pending=true -> wait for event -> initialized event => set Pending=false inside handler and access service. When the event gets handled the state is always set back to not pending. Sorry but i'm not sure if i get you right. – BionicCode Jul 15 '14 at 21:49
  • If the service calls back from a different thread and accesses shared members you can apply a lock. If you set the pending property (thread A) while a different thread with higher presedence (thread B) writes to it at the "same" time then the more relevant value (thread B) could be overwritten. – BionicCode Jul 15 '14 at 21:57
  • *precedence* ;) You check if IsInitialzed=false. If false you apply a lock and check it again (double-check) before finally setting a depending value. – BionicCode Jul 15 '14 at 22:03
  • After the lock is released the other thread can access it again and reset the values. Sorry I meant to apply the double check on the variable(?) holding the pending state (which maybe shared'cause the other thread resets it) before changing it. – BionicCode Jul 15 '14 at 22:09
  • Or you could use lazy initialization (using Lazy). (MSDN example link) http://msdn.microsoft.com/en-us/library/dd997286%28v=vs.110%29.aspx – BionicCode Jul 15 '14 at 22:30
  • Besides switching to Rx third-party library, is there any other standard/ common way to handle this scenario in C#? I'm even having problems in which search terms to use in order to google about it. – superjos Mar 04 '15 at 12:59

1 Answers1

1

You mention using events to do the communication between the service and the ViewModel, you could use Reactive Extensions (Rx) instead of using events and this has the ability to remove the race condition you describe above.

Put simply this turns the service from a pull-model into a push-model, it will push out data\events via a stream and allows you to compose LINQ queries over the stream. If you're not familiar with Rx there's plenty of good information out.

In this scenario using Rx I would have the service expose a property of IObservable<T>;, where T is your type (I guess some kind of State enum), the backing field for this property is the important part, this would be a ReplaySubject<T> with a size of one. What this means is anytime someone 'subscribes' to the property they will receive the last value published to the subject. This therefore means there isn't a race condition between publishing and subscribing to the stream.

This is probably a little easier to understand in code:

public enum State
{
    Initializing,
    Initialized,
}

public interface IMyService
{
    IObservable<State> Status { get; }
}

public class MyService : IMyService
{
    private ReplaySubject<State> _state;

    public MyService()
    {
        _state = new ReplaySubject<State>(1);

        _state.OnNext(State.Initializing);

        // Do initialisation stuff

        _state.OnNext(State.Initialized);

    }
    public IObservable<State> Status { get { return _state;  } }
}

The example only accounts for initializing the service on the current thread (ie synchronously), this means it would block the calling thread and I guess this would be the Dispatcher thread if this is a XAML based app.

If you require the initialization to be done asynchronously you would look to using either Observable.Create<T> or Observable.Start<T> to start the work on a background thread so that it doesn't block the dispatcher (UI) thread.

To consume this service you would do something like this is your ViewModel:

public class MyViewModel
{
    private State _state;

    public MyViewModel(IMyService myService)
    {
        myService.Status.ObserveOn(DispatcherScheduler.Current)
            .Subscribe(x =>
                        {
                            _state = x;
                        });
    }

    public bool IsReady { get { return _state == State.Initialized; } }
}

Now there isn't a race condition between the Service and the ViewModel.

There can be a lot to learn about Reactive Extensions but it is a very good way to handle asynchronous calls when you're implementing an MVVM application.

AwkwardCoder
  • 24,893
  • 27
  • 82
  • 152
  • Very nice! This is the first time I'm hearing about Rx. I like it. It seems to work like a charm, but I had to replace `DispatcherScheduler.Current` with `Scheduler.Default` (`Scheduler.CurrentThread` might work too?). It looks like the NuGet package for the main library didn't contain the Threading dll and I'm not entirely certain where to find that on the package manager. – jiminychris Jul 16 '14 at 16:21
  • Sorry forgot to mention it has been moved to a separate namespace, see this SO question http://stackoverflow.com/questions/6482997/rx-for-net-what-happened-to-scheduler-dispatcher – AwkwardCoder Jul 16 '14 at 16:29