Bindable LINQ: Threading

This weekend I checked in a pretty large set of changes to Bindable LINQ, the main goals being a focus on removing all multi-threading capabilities, and general simplification.

What I liked most about this commit is that the code was reduced. Before the changes, the Bindable LINQ solution was 20,829 lines of code; now it is down to 18,882 lines. Needless to say, this has led to a few breaking changes, and some of the tests don’t pass (yet), but it seems to work :)

Threading: Before

When I originally thought up Bindable LINQ, I had the idea of an Asynchronous operation. The idea was that you could setup a query over another data source, and Bindable LINQ would simply return an empty collection, then kick off a background thread, and as items are yielded, they’d be added to the Bindable LINQ result set and the UI automatically updated. I described it in my first video here:

The Asynchronous operation could also be applied last, so other Bindable LINQ operations could be done as part of the background thread. This meant that every Bindable LINQ class had to be aware of multiple threads.

Threading has it’s tricks, but it isn’t that hard. After some early trial and error and plenty of time debugging deadlocks, I settled on some key principals:

  1. Never hold a lock while calling code you didn’t write
    It might try to take a lock, while another thread holds that lock but wants to call your code. Deadlock.
    • This includes when raising events
    • This includes iterating over external items. I took snapshots of any external collection passed into Bindable LINQ, unless it was already a List<T>.
  2. Take snapshots of IEnumerables.
    I explained this in my post Snapshot Enumerators, which I still believe is the correct approach in the multi-thread aware scenario. You just can’t rely on Window 1 not to be looping through your collection while the user is clicking "Delete" in Window 2 (assuming they used different threads).
  3. Use locks when doing stuff to edit the collection
    Of course, since editing is meant to raise events, I created a "Transaction" system whereby only one thread could be performing a transaction at once, and once released, any events from changes made would be raised. It was complicated, but fun :)

As you can imagine, these principals caused a lot of overhead in the code, but I was absolutely convinced the multi-threading support was worth the cost. Then I changed my mind :)

The reason for my backflip came when, having used Bindable LINQ in a couple of projects, I realised that in all asynchronous related scenarios, the Asynchronous operator didn’t go far enough, or didn’t let me take all of the advantages of threading (it couldn’t use PLINQ, for example).

Instead, I found myself just doing a regular Bindable LINQ query over an ObservableCollection<T> which was empty, and managing the background tasks myself, and using the Dispatcher to route the new items to the ObservableCollection<T>. It was actually a simpler approach, and I realised the Asynchronous iterator wasn’t that useful.

Threading: After

Like WPF UI elements, Bindable LINQ queries are now bound to a Dispatcher. If updates come from source collections on the wrong thread, they’ll be routed to the right thread before processing. Most operations in Bindable LINQ, such as GetEnumerator() or Refresh(), require that they are called on the dispatcher thread. It might sound like a limitation, compared to the previous approach, but it made all of the queries a lot easier.

What this meant is I was able to cut out some of the problematic areas:

  1. All that code to avoid locks while making external code
    Many methods went from dozens of lines to two or three.
  2. Snapshots
    Since only one thread can be enumerating the collection at any one time, snapshots just aren’t needed.
  3. Locking
    When you ensure the object can only be touched from one thread, you generally don’t need to lock.

I think this can best be summed up by "YAGNI".

Dispatchers and Testing

A brief aside, but some issues can come up when combining the use of Dispatchers with unit tests. Here’s how I approach them in Bindable LINQ.

As I’m sure you know, components like the Background Worker or the Dispatcher work by sending messages from the current (background) thread to the message queue of the owning UI thread, which pulls them off the queue (just like a Button Click message) and processes them. This works great when you have a UI running, but not so great when you don’t, because there’s no message queue to read the messages from.

As a solution to this, I create the following components:

  • IDispatcher, an interface with methods like:
    • bool DispatchRequired();
    • void Dispatch(Action action);
    • void Dispatch<TResult>(Func<TResult> function);
  • WpfDispatcher, which adapts the WPF Dispatcher object to the IDispatcher interface.
  • SilverlightDispatcher, same as above, except for Silverlight. Since Silverlight doesn’t support synchronous invokes (you have to use BeginInvoke), I create a AutoResetEvent, and set it after the action has been processed, to effectively enable synchronous invokes.
  • TestDispatcher, which provides a simulator for the dispatcher.

It might sound like the simulated dispatcher is tricky, but in reality it turned out to be pretty simple. Instead of dispatching onto an owning thread, I just create a new thread each time - easy!

Suppose thread "A" is your UI thread, and thread "B" is your background thread. Here’s how it would work with a normal WPF dispatcher:

  1. Your UI is running on thread A
  2. You dispatch an operation from thread B
  3. It puts a message in the message queue for thread A
  4. Thread B waits (if it’s a synchronous Invoke) or continues (if it’s an asynchronous BeginInvoke)
  5. Thread A picks it up and processes it

In your tests, there are usually a couple of things you want to do:

  • Test that the thing you’re doing in the background is actually called on thread B
  • Test that any events you are raising are getting called on your foreground thread

So, our Test Dispatcher enables this:

  1. Your test is running on thread A
  2. You dispatch an operation from thread B
  3. It creates a new thread, and calls the operation on the new thread (thread C)
  4. Thread B waits (if it’s a synchronous Invoke) or continues (if it’s an asynchronous BeginInvoke)
  5. Thread C does the action.
  6. You test that the action happened on thread C

Since your tests won’t know about Thread C, the IDispatcher manages this. Recall that IDispatcher supports a DispatchRequired method, which returns true if it is called on a thread which is not the UI thread.

In our test dispatcher, we pretend that each of the subsequent threads we create (thread C, thread D, thread E), is also the owner thread. So in DispatchRequired, we check for the owner thread (A), or any of the threads we’ve used as fake Dispatcher threads. Pretty easy :)

That’s my general approach to testing multi-threaded components that rely on a dispatcher of some description. If you’d like to see the code, here’s some direct links:

Let me know what you think. To get the count of lines of code, I use a little utility I wrote some time ago here. Tomorrow night I’ll blog about some other changes I made in the name of simplification, as well as the new Switch operator :)

7 Responses to “Bindable LINQ: Threading”

  1. Hi Paul,

    It’s great to see that you ended up with the same approach as we did in the Eclipse data binding framework. Our IDispatcher is called Realm, but it really is the same idea - it abstracts from the “UI thread” notion, and observables check that you only access their state from that thread. Btw, we only support dispatching asynchronously - if you allow blocking waits (such as the dispatching of a function producing a result), this will make it possible to create deadlocks. So far, we haven’t come across a real need to have a synchronous dispatch.

  2. Hi Boris, that’s quite interesting to hear.

    One reason for synchronous dispatches is to stop indexes in collection changes events getting mucked around. For example, suppose your background thread inserts items 1 and 2 to a collection, and the collection raises two events with the indexes of the new items. If I route them asynchronously, it might happen that the insert event for item 2 is raised before item 1, and anything bound to it would get the indexes in the wrong order. I suspect the WPF dispatcher is smart enough to process the queues in the order they came in, but that’s a big assumption.

    I can’t think of any deadlocks that could occur using a synchronous invoke that couldn’t occur (albeit less frequently) using an asynchronous invoke - could you explain one of the scenarios?

    Thanks,
    Paul

  3. […] Bindable LINQ: Threading (Paul Stovell) […]

  4. […] Bindable LINQ: Threading - Paul Stovell Paul has a look at threading issues he had to overcome building his Bindible LINQ tool […]

  5. The WPF dispatcher preserves order of the invoke calls. In fact, if you look at the Dispatcher implementation, the synch invoke is implemented in terms of the BeginInvoke and waiting for it to finish.

    In all of our multi-threaded UI code, we only ever use Dispatcher.BeginInvoke.

    Actually, we use a higher-level abstraction — the SynchronizationContext. That way it’ll work in all thread-bound apps, including silverlight and ASP.Net.

    Just store a reference to SynchronizationContext.Current as a local member in your objects ctor (as it’s created on the UI thread) and use the context’s Post method. Fire and forget and it’ll go to either Control.BeginInvoke, Dispatcher.BeginInvoke, etc.

    –Oren

  6. Great post Paul! I am glad you shared your thoughts on this… very interesting.

  7. Hello. It is test.

Leave a Reply