I am looking for good ideas for implementing a generic way to have a single line (or anonymous delegate) of code execute with a timeout.
TemperamentalClass tc = new TemperamentalClass();
tc.DoSomething(); // normally runs in 30 sec. Want to error at 1 min
I'm looking for a solution that can elegantly be implemented in many places where my code interacts with temperamental code (that I can't change).
In addition, I would like to have the offending "timed out" code stopped from executing further if possible.
Well, you could do things with delegates (BeginInvoke, with a callback setting a flag - and the original code waiting for that flag or timeout) - but the problem is that it is very hard to shut down the running code. For example, killing (or pausing) a thread is dangerous... so I don't think there is an easy way to do this robustly.
I'll post this, but note it is not ideal - it doesn't stop the long-running task, and it doesn't clean up properly on failure.
What about using Thread.Join(int timeout)?
The really tricky part here was killing the long running task through passing the executor thread from the Action back to a place where it could be aborted. I accomplished this with the use of a wrapped delegate that passes out the thread to kill into a local variable in the method that created the lambda.
I submit this example, for your enjoyment. The method you are really interested in is CallWithTimeout. This will cancel the long running thread by aborting it, and swallowing the ThreadAbortException:
Usage:
The static method doing the work:
This is how I'd do it:
Some minor changes to Pop Catalin's great answer:
Overloads have been added to support signaling worker to cancel execution:
We are using code like this heavily in production:
Implementation is open-sourced, works efficiently even in parallel computing scenarios and is available as a part of Lokad Shared Libraries
This code is still buggy, you can try with this small test program:
There is a race condition. It is clearly possible that a ThreadAbortException gets raised after the method
WaitFor<int>.Run()
is being called. I didn't find a reliable way to fix this, however with the same test I cannot repro any problem with the TheSoftwareJedi accepted answer.