I need to stop the execution of a method if it has not completed within a limited period of time.
To do this work I can use the Thread.Abort
method in this way:
void RunWithTimeout(ThreadStart entryPoint, int timeout)
{
var thread = new Thread(() =>
{
try
{
entryPoint();
}
catch (ThreadAbortException)
{ }
}) { IsBackground = true };
thread.Start();
if (!thread.Join(timeout))
thread.Abort();
}
Given that I'm using .NET 3.5, is there a better way?
Edit: following the comments here my entryPoint
, but I'm looking for a good way for any entryPoint
.
void entryPoint()
{
// I can't use ReceiveTimeout property
// there is not a ReceiveTimeout for the Compact Framework
socket.Receive(...);
}
Answer depends on 'the work'. If work is something that can be safely stopped (i.e. not some I/O blocking operation) - use Backgroundworker.CancelAsync(...)
If you do have to cut hard - I'd consider using a Process
, in which case the Aborting
process is cleaner - and process.WaitForExit(timeout)
is your friend.
Suggested TPL is great but unfortunately does not exist in .Net 3.5.
EDIT: You can use Reactive Extensions to follow Jan de Vaan's suggestion.
Here is my 'action timeout' snip - it's mainly here for others to comment on:
public static bool WaitforExit(this Action act, int timeout)
{
var cts = new CancellationTokenSource();
var task = Task.Factory.StartNew(act, cts.Token);
if (Task.WaitAny(new[] { task }, TimeSpan.FromMilliseconds(timeout)) < 0)
{ // timeout
cts.Cancel();
return false;
}
else if (task.Exception != null)
{ // exception
cts.Cancel();
throw task.Exception;
}
return true;
}
EDIT: Apparently this isn't exactly what OP wanted. Here's my attempt to devise a 'cancelable' socket receiver:
public static class Ext
{
public static object RunWithTimeout<T>(Func<T,object> act, int timeout, T obj) where T : IDisposable
{
object result = null;
Thread thread = new Thread(() => {
try { result = act(obj); }
catch {} // this is where we end after timeout...
});
thread.Start();
if (!thread.Join(timeout))
{
obj.Dispose();
thread.Join();
}
return result;
}
}
class Test
{
public void SocketTimeout(int timeout)
{
using (var sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
{
Object res = Ext.RunWithTimeout(EntryPoint, timeout, sock);
}
}
private object EntryPoint(Socket sock)
{
var buf = new byte[256];
sock.Receive(buf);
return buf;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With