Showing posts with label threading. Show all posts
Showing posts with label threading. Show all posts

Sunday, January 27, 2008

Improving NotifyWorker (and why blogging makes me smarter)

My current day job consists of writing middleware and web-based LOB software for an actuarial services company.

David is my primary collaborator and a fellow blogger. We get along amazingly well, but every once in a while, we disagree. The amazing thing, though, is how we handle disagreements.

I'm at a point where I look forward to disagreement! For a reason that I hope more people can come to realize.

If we disagree about how something should work, it's almost always an opportunity for improvement. Specifically, at least one of the following is likely to happen:

  • I get smarter
  • He gets smarter
  • The code gets better

Quite often, it's all three. I know this sounds like motivational speaker talk or corporate training fodder, but it's true. The fact that we often discuss our disagreements with explicit reference to masters is also helpful.

I blog for similar reasons. I'm far from a CLR, C# or WPF expert, at least relative to the experts I've had the opportunity to work with.

I'm just a geek trying to figure things out and sharing as I go. Hopefully what I share is helpful. Often, though, blogging has self-serving benefits. Just taking the time to write down explanations for what I'm doing forces me to rationalize edge cases.

If I had never blogged the recursive flattening craziness, I would have never have seen all of the edge cases I had missed the first time out.

Anyway, to my point.

Simon was kind enough to point out a deadlock in my NotifyWorker code.

FYI: At this point, looking at the code will be quite helpful.

I was doing a Thread.Join() in the middle of a lock. Of course, if the thread in question is waiting on the lock which is held, the thread will never exit. The result: the Join() call will never return.

Deadlock, indeed.

Props to Simon for pointing out this problem.

I moved the Join() outside of the lock and thought I'd fixed the problem.

Maybe, but I also realized another problem.

  • Dispose is likely called from the UI thread.
  • Dispose calls Join on my worker thread as discussed above.
  • The worker thread does Dispatcher.Invoke twice.

What happens if Dispose is called between my check for m_disposed and when the Invoke actually gets to the UI thread?

Dispose will be tying up the UI thread waiting for Join() to return. The worker thread will never terminate because it's waiting for Invoke to get to the UI thread.

Deadlock again.

Darn.

The solution: Move from Dispatcher.Invoke to Dispatcher.BeginInvoke.

BeginInvoke returns an instance of DispatcherOperation. This class has an Abort method which can be used to abort a pending BeginInvoke.

I now have an instance field containing the pending operation, if one exists, which can be aborted via Dispose before the call to Join. I also now enforce that Dispose must be called on the UI thread (by adding a call to VerifyAccess). This ensures that Abort is not called while the worker is synchronized to the UI thread.

After some careful uses of DisaptcherOperation.Wait and some paranoid null checks, I think I'm okay. 

As an aside, I also noticed that Dispose() will throw in the case where NotifyNewWork() has never been called. I fixed that, too.

*Sigh*

Threading code is tough. I had to stand up and pace around a few times as I mentally worked through possible edge cases.

As I've said before, I think this implementation is better, but it would be a stretch for me to claim it's correct. Hopefully, it's more correct.

Please keep the questions, comments, and feedback coming (after you take a look at the post about contacting me).

The code will get better and we'll all get smarter.

 

Happy hacking.

Tuesday, January 22, 2008

Responsive UI with Unresponsive Data: NotifyWorker

Yes, I finally got off my SelectRecursive kick. This is penance.

The 3-box Visio Diagram

How many user interfaces do you design that follow this pattern?

image

Okay, almost all of them.

A frequent refrain from users (well, at least me):

Regardless of what you're doing behind-the-scenes, the interface should never hang, stutter, or lag. Ever.

Easily said, right?

Well, while hacking on one of my side projects, I ran into this problem.

I put on my "framework guy" hat and asked, "Can I formalize this into a pattern?"

My answer: NotifyWorker.

Now before I get into NotifyWorker, I should mention BackgroundWorker: a frequently used and well thought-out component supplied by our friends in the Baseclass Library (BCL) for this kind of thing.

The trick performed by BackgroundWorker is simple, but important: allow start/stop/cancel of a task on another thread. It also keeps developers sane who have to deal with strict rules about what can only be done on the UI thread.

The type of tasks for which NotifyWorker was designed fit into a special niche that I think BackgroundWorkre misses:

  • Tasks that are long enough to lag the interface (0.1+ seconds) but are too short to require tracking of percent complete (so shorter than, say, 5 seconds).
  • Tasks that are repeated constantly as the UI updates. Think of recalculating a math/physics model or checking a server-hosted word list for a type-a-head find control.
  • Tasks where the work to be done is--in relative terms--longer than the work to update the user interface. If the task takes 0.1 seconds, but updating the 1,000 controls in your window takes 2 seconds, you should start by tweaking your architecture before using NotifyWorker.

How does it work?

(Reflector is how I learn all of my new APIs.)

image

The constructor takes three parameters that outline the diagram above and the workings of NotifyWorker:

  • Func<bool> prework: this is a delegate that is called on the Dispatcher (UI) thread in a WPF application. Delegate passing is a trick I use a lot, and you should, too. The method does the work to take interesting parameters from the UI (control values, etc.) and puts them in a spot where NotifyWorker can safely play on a non-UI thread. If you decide there is nothing interesting to do, you can return false, telling NotifyWorker "never mind".
  • Action work: this is where the magic happens. This function is called on a background thread which will leave your UI nice and responsive. Be super careful that 'work' only touches state (fields, etc) that you've safely set aside during prework.
  • Action postWork: the last box in our diagram. It takes the work done in 'work' and updates the UI accordingly. This method, as well as 'preWork', synchronizes the UI and background threads, so you don't have to worry about locking.

How do you kick things off? Call NotifyNewWork. This method can be called often, if you want. Put it in the 'Changed' handler of your favorite Slider or TextBox. If NotifyWorker is idle, it will wake up and immediately call preWork. If NotifyWorker is busy, it'll loop right around to get new input values as soon as postWork is done.

A demo

image

Sexy, huh?

The scenario is simplistic and contrived, like so many good demos.

Both sets of UI do the same thing: take the values from two sliders and sum them. Not too complicated.

For some strange reason, the sum 'routine' takes 0.25 seconds to return a result.

Maybe it's that new math...

Eh, it's probably the Thread.Sleep(250) I put in the method.

Anyway, use your imagination. You'll notice that the 'slow' UI is, well, slower. It lags a bunch as you drag the sliders since it's calling the expensive sum method on the UI thread.

The NotifyWorker controls do much better because the expensive call is hidden off-thread.

Simple, but useful.

Odds and ends

You'll notice a LastClientExceptionEventArgs property and a ClientException event. These are designed to make it a bit easier to handle non-critical exceptions during 'work'. The demo code actually shows this off pretty well.

You'll also notice that NotifyWorker implements IDisposable. Dispose will make sure to end any background work when you're done with NotifyWorker.

Under the covers, NotifyWorker uses LockHelper and some of the pulse/monitor tricks I wrote about a few months ago.

That's about it.

Since NotifyWorker is hard-wired to the notion the Dispatcher, it lives in J832.Wpf.BackOTricksLib. The demo is in the Bag-o-Tricks app under NotifyWorker.

I'm not going to do an official release (zip with binaries/source) of the bag for this sample. It's cool, but not cool enough to warrant a whole new drop.

It also gives you an excuse to play with SVN, if you haven't already. You can always just manually download the code from my SVN share using your browser, too.

Let me know if this works well for you.

 

Happy multi-threaded hacking!

 

Note: I've had some funky auth issues with Firefox on the SVN server lately. Let me know if you have any trouble.

Tuesday, November 13, 2007

Going beyond Monitor.Enter/Exit (C# lock) with LockHelper

Sample code: LockHelper.cs [6KB]

Debugging threading issues is painful.

Really painful.

One of the most painful problems: dealing with deadlocks--waiting forever on a Monitor.Enter (C# lock) and not knowing which thread already has the lock.

I tried to dig in on this on the CLR Base Class Library Forum. I was hopeful, since Java has a method [Thread.holdsLock(obj)] that returns the holder of the current lock

Sadly, .NET lacks this functionality.

Enter a can-do attitude: why not build it myself.

Enter LockHelper.

Goals:

  • Identical semantics to Monitor.Enter/Exit
  • Enable other Monitor features (Pulse, Wait)
  • Close to identical syntax to C# lock
  • Ability to know, given an instance of LockHelper, the current owning thread
  • Other conveniences (CheckAccess and VerifyAccess)

Wrapping Monitor.Enter/Exit isn't that hard. As you see with the implementation, it's pretty easy to leverage IDisposable + the C# using statement to get syntax that is close to lock.

Instead of:

public void Foo()
{
    lock(m_lockObject)
    {
        //do stuff
    }
}

private readonly object m_lockObject = new object();

Do this:

public void Foo()
{
    using(m_lockObject.GetLock())
    {
        //do stuff
    }
}

private readonly LockHelper m_lockObject = new LockHelper("foo");

GetLock() returns a private class that implements IDisposable. The using block has identical try/finally semantics to the lock keyword. (See this article in the C# Programming Guide for details.)

I had to be religious about storing away Thread.Name for the current thread at all times. While debugging, I found that VS was often unable to evaluate the property of the owning thread.

So now I have enough plumbing to figure out which thread has a lock on my lock object. Cool.

What else?

Exposing Pulse and Wait was pretty easy. Beyond these basics, I stole the CheckAccess/VerifyAccess ideas from WPF.

Often times one will have private helpers in a class that access/modify the state of a class. Often times these methods (should) run under the assumption that they were called in the context of a lock.

The simple way around this is to re-lock the object inside the helper method, but this can be a source of deadlocks and really doesn't help maintain the implementation contract.

What one wants: a way to assert that the calling thread owns a lock.

Done!

CheckAccess returns true if the current thread has the lock. Otherwise, false.

VerifyAccess goes a step further and throws an exception if the calling thread doesn't own the lock.

Pretty cool, huh?

Note: I was not on the CLR team at Microsoft. I was not a developer at Microsoft, just a lowly PM. I'm pretty confident this works. At least I haven't hit any issues with it. Please be careful throwing this in your own projects. This is certainly out of the realm of advertised best-practices from MS.

It works for me, though.

Let me know what you think.

Happy hacking!

Friday, October 26, 2007

Threading fun: Monitor.Wait, Monitor.Pulse

Threading is pretty scary. An solid grasp of threading, as a brilliant dev lead at Microsoft once told me, was one thing that consistently separated the "men/women from the boys/girls" in the engineering discipline.

Here's my attempt to sound adult. (Forgive me if my voice cracks.)

The Scenario: You have a bunch of threads running around doing work--in this case, adding random numbers to a collection. You have another thread with the aggregation job: take all of the numbers in the collection, add them to a running total, and clear out the collection.

This is a simplification of a problem I was faced with on my current gig: handle multiple "users" via separate WCF connections (coming in on separate threads). Aggregate their work requests and process them on a 'worker' thread. All while staying super responsive.

So you always have the one thread that's waiting around for work. How does it wait? The simple answer would be a while-true loop that's always polling.

That'll peg a thread pretty quick while doing a bunch of unneeded locking of your synchronization object. One could add some sleep statements to the loop to minimize the impact, but that feels like a bandage.

What one wants: a way to have the processing thread "wait" to until there actually is work to do.

Enter Monitor.Wait and Monitor.Pulse.

Mike Woodring does a pretty good job of explaining this (with a very funny title/analogy), but I really wanted a fully baked and un-contrived code sample.

So here it is. In exactly 100 lines of code.

MonitorWaitPulseFun.cs [3KB]

Wait and Pulse both must be called in the context of a lock (Monitor.Enter/Exit) for the provided object.

Wait [Line 58] basically gives up the lock (and allows other code blocked by the lock to run) and waits until Pulse [Line 43] is called on another thread. The 'wait' thread then gets back in line for the lock and continues execution from where it left off.

It's a bit weird to accept that a lock for a given object is temporarily given up between the curly braces, but that's what happens.

The only hiccup I ran into was realizing that one really needs to be careful to make sure pulse is called enough, especially when shutting down. 'Wait' will wait forever if it doesn't get kicked.

A note: I go this all working with a WaitHandle initially (specifically, AutoResetEvent), but I realized it was a lot more involved and (after some research) a lot heavier than I needed. WaitHandle actually wraps some Win32 stuff that goes way beyond what I need for this scenario.

Anyway, here's my foray into non-WPF technical blogging.

Interesting? Helpful?

Happy hacking...