Pulled Apart - Part III: Get on the bus!

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.

[...] 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 [...]

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Post new comment

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account associated with the e-mail address you provide, it will be used to display your avatar.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • Syntax highlight code surrounded by the <pre class="brush: lang">...</pre> tags, where lang is one of the following language brushes: as3, applescript, bash, csharp, coldfusion, cpp, css, delphi, diff, erlang, groovy, jscript, java, javafx, perl, php, plain, powershell, python, ruby, sass, scala, sql, vb, xml.

More information about formatting options