Copyright 2008-2009, Paul Jackson, all rights reserved
I really wasn’t planning on writing a post about Future<T> … really … but I had a “damn, I wish”-moment at work today. Yes, another one – our current project is in Test and we’re finding some threading defects. The particular one I worked on this morning was easy enough to find and fix, but I always seem to have the .Net 4 Parallel Extensions at the back of my mind these days, so as soon as I saw what the problem was, my reaction was: “Oh, okay, I just need to change that to a Future and … damn, I wish we could actually use that now.”
In this particular application we have a number of client-side services that use ThreadPool to initialize themselves on startup – as each service is instantiated. Other parts of the app make use of the services when needed. So the important parts of the class in question looked something like this when I got to it this morning:
The problem that was occurring was that the consumer of this service was intermittently (and rarely) getting a NullPointerException. Obviously, the initialize() method was sometimes taking enough time that the MyStuff property was still null when the first consumer needed the value – and, clearly, this class didn’t follow the pattern we’ve established elsewhere in the application to avoid just this situation. Why didn’t it follow that pattern? Well, there was a comment in the getter that explained that:
So, apparently, the developer who originally coded this several months ago was in a hurry and lost track of the task to go back and add the appropriate code. He probably didn’t add a Team Foundation Server WorkItem to ensure that work got done.
Those of you who are both observant and clever will note my name in the About Me section to the left and deduce that my middle name begins with an A. Yes, it was me. In my defense, someone needed the service and I was in a hurry.
I made the necessary changes to ensure that if someone tried to access the value before the initialization completed, things would block there and all is now well with that defect being closed, but it nags at me a bit how much easier Future<T> would have made things.
Future<T> allows you to get a return value from a parallel Task and block when a consumer tries to access that value if it isn’t available yet. The syntax is very similar to Task:
What’s actually returned is a Future<T>, so in the above example, result is of type Future<int> – and the return value of the delegate is accessed through the Value property. Accessing the Value property blocks until the delegate has finished running and returned a value.
So using Future<T>, my service would look very similar to the original code that was broken, but would actually work properly and wouldn’t be cluttered with all the plumbing code to wait on the background thread:
Damn, I wish …