Note: 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.
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.