簡體   English   中英

如何在特定時間后停止執行某個方法?

[英]How to stop the execution of a method after a specific time?

如果方法在一段有限的時間內沒有完成,我需要停止執行。

為了完成這項工作,我可以用這種方式使用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<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;
    }
}

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<Token> entryPoint, int timeout)
        {

            Token token = new Token();

            var thread = new Thread(() => entryPoint(token)) { IsBackground = true };

            thread.Start();

            if (!thread.Join(timeout))
                token.Cancel = true;
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM