如何在特定时间后停止执行某个方法?

如果方法在有限的时间内没有完成,我需要停止执行。

为了完成这项工作,我可以用这种方式使用Thread.Abort方法:

 void RunWithTimeout(ThreadStart entryPoint, int timeout) { var thread = new Thread(() => { try { entryPoint(); } catch (ThreadAbortException) { } }) { IsBackground = true }; thread.Start(); if (!thread.Join(timeout)) thread.Abort(); } 

鉴于我使用的是.NET 3.5,还有更好的方法吗?

编辑:在这里注释我的entryPoint ,但我正在为任何entryPoint寻找一个好方法。

 void entryPoint() { // I can't use ReceiveTimeout property // there is not a ReceiveTimeout for the Compact Framework socket.Receive(...); } 

答案取决于“工作”。 如果工作是可以安全停止的(即不是一些I / O阻塞操作) – 使用Backgroundworker.CancelAsync(...)

如果你必须努力削减 – 我会考虑使用一个Process ,在这种情况下, Aborting进程更干净 – 而process.WaitForExit(timeout)是你的朋友。

建议的TPL很棒但很遗憾在.Net 3.5中不存在。

编辑:您可以使用Reactive Extensions来遵循Jan de Vaan的建议。

这是我的’动作超时’剪辑 – 它主要是供其他人评论:

  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; } 

编辑 :显然这不是OP想要的。 这是我试图设计一个'可取消的'套接字接收器:

 public static class Ext { public static object RunWithTimeout(Func 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; } } 

Thread.Abort通常是一个糟糕的解决方案 。 您应该使用一个标志来指示操作是否被取消,并在您的entryPoint函数中进行检查。

  class Program { static void Main(string[] args) { RunWithTimeout((token) => { Thread.Sleep(2000); if (token.Cancel) { Console.WriteLine("Canceled"); } }, 1000); Console.ReadLine(); } private class Token { public bool Cancel { get; set; } } static void RunWithTimeout(Action entryPoint, int timeout) { Token token = new Token(); var thread = new Thread(() => entryPoint(token)) { IsBackground = true }; thread.Start(); if (!thread.Join(timeout)) token.Cancel = true; } }