17 Aug 2010

onebit_26Note: This is part of a series, you can find the rest of the parts in the series index.

One of the aspects of Pull is that it had to be multi-threaded, because things like downloading a massive podcast shouldn’t lock up the UI. Threading has become pretty easy in .NET 4 thanks to things like PLINQ or Parallel Extensions. However cross thread communication hasn’t gotten easier in .NET 4.

My idea to solve this was to create a internal bus – which is just an implementation of the pub/sub pattern. A bunch of subscribers register with the bus for a specific message type and when a message is given to the bus, it passes it to the correct subscribers.

image 

First thing I did was create a simple singleton instance of my bus class:

internal class Bus
{
    private static Bus bus = new Bus();

    private Bus()
    {
        publisher = new Publisher();
    }

    public static Bus GetBus()
    {
        return bus;
    }        

This ensures that all threads get the same instance. Inside my bus class I implement the new .NET 4 IObserver/IObservable interfaces which gives me all the pub/sub magic. This is all internal to the bus class so that usage in my application is just with bus. For example the methods for registering a subscriber is, which hides the pub/sub concept completely.

public void Register<T>(DataAction actions, Action<T> method, Control control = null)
{
    publisher.Subscribe(new Subscriber<T>(actions, method, control));
}

public void Register(DataAction actions, Action method, Control control = null)
{
    Action<object> fakeMethod = value => { method(); };
    this.Register(actions, fakeMethod, control);
}

One of the options when registering a subscriber is you can is pass in a control, which I use for handling objects owned by other threads which makes it very easy to update the UI.

Broadcasting to all subscribers who have registered for a message type is handled by a very simple method:

public void Broadcast<T>(DataAction action, T data)
{
    publisher.Update(action, data);
}

public void Broadcast(DataAction action)
{
    this.Broadcast<object>(action, null);
}

To identify the type of message I am using an enum, which I do not feel too great about. The advantage of using enum’s is that there is no magic strings which the compiler can’t identify (i.e. if I mistype a message, the compiler tells me) and that I can use flags to broadcast multiple messages at once. However the downside of enum’s means adding a new message means editing the list of enum’s which isn’t so great.

Final Thoughts

Overall I am exceptionally happy with the bus as it solved so many problems I have had with multi-threaded applications and I think should be a standard in application design in future.

Comments

Pulled Apart - Part XI: Talking to yourself is ok, but answe's picture

[...] get the right ID (see line 1 about – the NotifyMessageID) I then act on it. In my case I use the bus to tell IMPF that there is a new [...]

Add new comment