Calling methods with a time out   Leave a comment

I was implementing a communication with a device via RS232 and came across the possibility of not having any response. Just like every time one depends on someone else’s volatile response.

I looked around a bit and all I found was a little confusing and, as usual, very little generic. I put my hands on it and came up with this implementation that I now use, maybe, a little bit too much.

The Delegates

If you’re in .Net 2.0 Func<T> and Action are not yet implement. Actually, they’re just  particular delegates that are so often used that were considered for .Net 3.0 (and posterior) inclusion. Their implementation is as follows:

public delegate T Func<T>();
public delegate void Action();

 

Implemention

The implementation couldn’t be simpler and is based on the ability to call delegates asynchronously with BeginInvoke and WaitHandle.WaitOne method provided by IAsyncResult.AsyncWaitHandle. Note that BeginInvoke and EndInvoke are provided by the C# compiler in it’s delegate keyword. If we at the IL generated by the compiler for Func<T> it becomes clear, even if you don’t know anything about IL:

.class auto ansi sealed nested public Func<T>
    extends [mscorlib]System.MulticastDelegate
{
    .method public hidebysig specialname rtspecialname instance void .ctor(object 'object', native int 'method') runtime managed
    {
    }

    .method public hidebysig newslot virtual instance class [mscorlib]System.IAsyncResult BeginInvoke(class [mscorlib]System.AsyncCallback callback, object 'object') runtime managed
    {
    }

    .method public hidebysig newslot virtual instance !T EndInvoke(class [mscorlib]System.IAsyncResult result) runtime managed
    {
    }

    .method public hidebysig newslot virtual instance !T Invoke() runtime managed
    {
    }

}

If you’re wondering about System.MulticastDelegate

So the implementation goes like so for methods with a return object:

static T RunMethodWithTimeOut<T>(int millisecondsToWait, T timeoutResult, Func<T> method)
{
    var asyncResult = method.BeginInvoke(null, null);
    if (!asyncResult.AsyncWaitHandle.WaitOne(millisecondsToWait))
        return timeoutResult;
    return method.EndInvoke(asyncResult);
}

 

And with void return, a boolean is returned indicating if the method ended which might be handy:

static bool RunMethodWithTimeOut(int millisecondsToWait, Action method)
{
    var asyncResult = method.BeginInvoke(null, null);
    if (!asyncResult.AsyncWaitHandle.WaitOne(millisecondsToWait))
        return false;
    return true;
}

 

Testing

For testing I implemented these two methods that use both implementations of RunMethodWithTimeout:

static string TestStringTimeout(int timeoutSeconds, int methodSeconds, 
							string timeoutResult, string methodResult)
{
    return RunMethodWithTimeOut<string>(timeoutSeconds * 1000, timeoutResult,
			() => { Thread.Sleep(methodSeconds * 1000); return methodResult; });
}

static bool TestVoidMethod(int timeoutSeconds, int methodSeconds)
{
    return RunMethodWithTimeOut(timeoutSeconds * 1000, 
			() => Thread.Sleep(methodSeconds * 1000));
}

 

And run them in a console application testing all who-arrives-first scenarios:

static void Main(string[] args)
{
    Console.WriteLine(TestStringTimeout(1, 2, "Timed out!", "++Success"));
    Console.WriteLine(TestStringTimeout(2, 1, "Timed out!", "++Success"));
    Console.WriteLine(TestStringTimeout(1, 1, "Timed out!", "++Success"));
    Console.WriteLine();
    Console.WriteLine(TestVoidMethod(1, 2) ? "++Success" : "Timed out!");
    Console.WriteLine(TestVoidMethod(2, 1) ? "++Success" : "Timed out!");
    Console.WriteLine(TestVoidMethod(1, 1) ? "++Success" : "Timed out!");
    Console.ReadLine();
}

 

That’s wrap.

 

Heads up! Update

I was happily using this method when I started to run into some troubles. Now, it is quite obvious but I missed this very important issue: the method whose result is dismissed because it timed out has to be stopped.

In these cases, an overload providing and end method is most useful. Something like so:

static T RunMethodWithTimeOut<T>(int millisecondsToWait, T timeoutResult, Func<T> method, Action end)
{
    var asyncResult = method.BeginInvoke(null, null);
    if (!asyncResult.AsyncWaitHandle.WaitOne(millisecondsToWait))
    {
        end();
        return timeoutResult;
    }
    end();
    return method.EndInvoke(asyncResult);
}

 

And invoking would look something like this:

var isTimedOut = false;
var result = RunMethodWithTimeOut<string>(1000, "TimedOut",
    () =>
    {
        string successResult;
        do successResult = DoSomeProcessingThatMightNeverBeGood();
        while (null != successResult && !isTimedOut);
        return successResult;
    },
    () => { isTimedOut = true; });
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: