Towards cleaner code, a C# Asynchronous Helper (Pt 1 of 3)
Posted by Nicholas Brookins on 17 September, 2008// Series Introduction
I’m a sucker for clean and beautifully groomed code. In my experience maintaining a large code base with few resources, it is in fact the only way to keep sanity and keep from sliding into a pit of spaghetti. I’ve been on a push to find areas of necessarily messy or repeated code and find ways to make them more elegant and maintainable - this is the first in a series* of small classes and helpers that I kick myself for not doing sooner.
UPDATE: This post is now an article on CodeProject.
// The Problem at Hand
In any reasonably large application there are a lot of times when you need to perform a quick task asynchronously. One use off-hand is application that saves a log or status report to file on start-up. The operation is slow in relative terms since it involves file I/O, and we don’t have to worry much about other code paths depending on it. Making it asynchronous will speed up our start time with no risk of side effects.
// The Obvious and Ubiquitous Solutions
The .NET Framework makes this quite easy, we’ll show a few ways to accomplish it. However there are gotchas and keeping track of everything can lead to messier code, so I’ll introduce a helper class to make our lives easier. Of course exception handling and such is excluded from these examples for brevity.
1. Brute Force - create a new thread: Besides the chattiness here, this is not the most efficient way to get this done, unless you have a pretty long running task. For every action, a new thread with context and stack space will be created, just to be used for a short period. More effective is to utilize the .NET ThreadPool, and let it reuse a few preallocated threads on your behalf.
private void SaveReport() {
statusReport.Save(); //This takes a bit of time
Console.WriteLine("Status report saved!");
}
ThreadStart ts = new ThreadStart(SaveReport);
Thread t = new Thread(ts); <br />
t.IsBackground = true; <br />
t.Start();
MethodInvoker dlg = new MethodInvoker(SaveReport);
dlg.BeginInvoke(null, null);
3. Anonymous Method. I’ll also note that in .NET 2.0 we can use an anonymous method, saving us from defining the method separately. functionally this operates the same way as the previous.
delegate {
statusReport.Save();
Console.WriteLine("Status report saved!");
}.BeginInvoke(null, null);.
There is a problem with both of these examples as well, besides their messiness. The BeginInvoke method takes two parameters, a AsyncCallback for notifying when the operation completes, and an object that is passed through to that callback for the callers purposes, typically the original delegate. Now creating a callback just adds more trouble to this whole exercise, particularly if you do not need to know exactly when the operation completes. However, although not documented well, I’ve seen issues if the callback is not used to call EndInvoke, as such:
private void ReportCompleted(IAsyncResult result) {
if (!result.IsCompleted) return;
MethodInvoker dlg = result.AsyncState as MethodInvoker;
dlg.EndInvoke(result);
}
//...//
AsyncCallback asc = new AsyncCallback(ReportCompleted);
MethodInvoker dlg = new MethodInvoker(SaveReport);
dlg.BeginInvoke(asc, dlg);
No major issues now, but again - this gets very messy, especialy once you start creating a couple 5 line methods everywhere for each task.
WaitCallback wc = new WaitCallback(SaveReport);
ThreadPool.QueueUserWorkItem(wc);
This is much more concise, but without the control over the process that we have in the above examples. A larger problem that I haven’t discussed is that any of these examples can fail spectacularly, or sometimes silently - any exceptions from your invoked methods will vanish into the ether. Once error handling (and logging, right?) is applied to both the action being performed, and the action of invoking it, and possibly to ending the invoke, we have a lot of code to just make a one-liner action happen safely asynchronous.
If this does fail, you may want to then attempt the action with a dedicated thread to make sure it works if the ThreadPool is not cooperating, that’s more code to bandy about.
A more subtle limitation I started to run into is the matter of reentrance. In the above example we are periodically saving a status report. What happens if it gets delayed? Its quite possible that the next time you invoke it the prior attempt is still in process, all kinds of mayhem could ensue. Now we need to add even more code for blocking and thread safety.
private readonly object reportLock = new object();
private void SaveReport(){
lock(reportLock){
/* extra credit for why we didn't just lock our status report object! */
statusReport.Save();
Console.WriteLine("Status report saved!"span>);
}
}
Wait a second though - if one status report is a few minutes behind, we don’t need one to follow right on it’s tail. We also want to avoid getting multiple ThreadPool threads stacked up on each other, preventing other tasks. Let’s instead make this blocking into a bypass, and skip the next action if we get backed up:
7. Thread-Safety: Bypass.
private readonly object reportLock = new object();
private void SaveReport() {
if (!Monitor.TryEnter(reportLock)) return;
//if it is locked, just dump outta here..
try {
statusReport.Save();
Console.WriteLine("Status report saved!");
} finally {
Monitor.Exit(reportLock);
}
}
If you aren’t familiar with this syntax, the C# lock statement is just a shortcut for using the Monitor.Enter and Monitor.Exit calls appropriately. In this case we used the monitor class directly, with TryEnter so that it didn’t block forever.
So now we have at least seven different ways of skinning this cat, all with pros and cons. Every time you need to run a task asynchronously you must evaluate multiple options, worry about exceptions, copy and paste (ack!) more chunks of similar code around, and then maintain that code that clutters up the flow of your logic.
What if we had some kind of magical helper class that had the power of any of the examples above, but was also incredibly concise? It would put all of this power in one place, so troubleshooting and changes and error handling and tweaks could be concentrated in one place. Come to think of it, such a class might even heal sick puppies! Here’s how we would use it:
Async.Do(SaveReport);
What? How could it be that easy? Is this possible? Yes, all this can be yours, and more. .NET automatically takes any void method with no parameters and invisibly makes a delegate for it, which is how the above works by passing a method name, we can also pass delegates or anonymous methods.
Async.Do(delegate {
Console.WriteLine("I'm in an anonymous delegate!");
statusReport.Save();
});
// More advanced Async class examples
With some overloading and fancy footwork, we can also do any of the following:
/* this takes care of any of our locking and blocking and thread-safety woes. The ReentranceMode enumeration also has options for 'Stack' and 'Allow' */
Async.Do(SaveReport, ReentranceMode.Bypass);
/* The bool parameter 'useReturnValue' instructs the helper to track the return value of your delegate/method if you ask for it later from the IAsyncResult that is returned : */
IAsyncResult result = Async.Do(SaveReport, true);
//do other stuff in meantime...
// ...and if the action is not completed, wait for it to finish
if (!result.IsCompleted) result.AsyncWaitHandle.WaitOne();
Console.WriteLine("My result was: " + result.ReturnValue);
/* Methods that take parameters can be wrapped in an anonymous method, the parameter will be psuedo-curryed for us by the framework. If the return value is important, we can also use a return inside the anonymous method! */
Async.Do(delegate { return GetAnObject("A string parameter"); });
/* our most advanced method signature has all of the options, as seen below */
Async.Do(
SaveReport, //our delegate or method
false, //track return value?
this, // a state object to be tracked with the IAsyncResult
true, /* Use ThreadPool? true will attempt to use the threadpool, then fall back to a thread.
False always uses a thread, for use with long-running tasks.*/
ReenteranceMode.Stack); //our enum controlling how we handle multiple calls to the same action.
Check back soon for the thrilling conclusion, and let me know what you think!
So there it is, the best .NET Asynchronous helper class a geek could ask for. All the power of any other methodology with none of the bloat and maintainability issues. This class has greatly simplified code flow and literally cut thousands of lines of code from an large application. I’ve taken long enough just explaining the need and usage of the class, I’m going to save the implementation (and source code) for the next post.
![]()

Subscribe to Posts
Subscribe by Email
September 18th, 2008 a.t 5:53 am
I think you’ve covered most scenarios I’ve run across when I want to process asynchronously. However, I’d add some sort of control over termination. Something akin to the Thread.Abort method and the Thread.IsBackground property. Sometimes, you want your execution to hold up your program closing, and other times you just don’t care. Cheers.
September 18th, 2008 a.t 4:47 pm
Good observation.
The thread it creates is always background.. I figure if this is something important enough to hold your app, you should probably be handling it directly. It’d be easy enough to add control over that if needed though.
The IAsyncResult that is returned is an instance of a ‘AsyncRes’ class. It has a method CancelOrAbort(), an enum indicating success and how the task was executed, and then properties for ReturnValue, TimeCreated, TimeStarted, TimeRunning, and TimeCompleted.
I’ll get in to that part more in part 2!
June 24th, 2010 a.t 8:22 pm
Had a Hayward since pool was put in ~3 years ago. Was plagued with problems, every little thing from pump failures to plastic clips breaking to getting tangled. For two years I had a bungee cord keeping it together. Then the Hayward … snap to change out (am utilizing similar pump), in two months had not gotten stuck; picks up even the smallest particles, very straightforward to empty the bag.