【问题标题】:How to abort a long running method?如何中止长时间运行的方法?
【发布时间】:2012-06-05 09:00:51
【问题描述】:

我有一个长时间运行的方法,我想在其中添加超时。这样做可行吗?比如:

AbortWaitSeconds(20)
{
    this.LongRunningMethod();
}

当达到 20 秒时,该方法将被中止。该方法没有循环,我没有对该方法的控制/代码。

【问题讨论】:

  • 你是指一个操作系统进程,比如一个外部应用程序,还是只是在你的应用程序内部,在同一个线程或其他线程中的一些长计算?
  • @EugeneRyabtsev 在我的应用程序中的同一线程中进行长时间计算。

标签: c# .net-4.0 process


【解决方案1】:

有关通用解决方案,请参阅 my answer to this question

【讨论】:

  • @JohnIsaiahCarmona:可能,但我对线程了解不多;p 可能存在细微差别。现在阅读它。
  • while (t.ThreadState != ThreadState.Running) 行有什么作用?
  • @JohnIsaiahCarmona:这只是确保线程在开始“倒计时”之前已经真正开始。假设一个线程需要 20 毫秒才能启动,并将超时限制为 10 毫秒,那么线程甚至都不会启动。对于更长的超时,不需要。
  • 谢谢,我使用您的代码,但我使用 Thread.Join 而不是 AutoResetEvent。不知道有没有区别。再次感谢你的帮助。 :)
【解决方案2】:

试试这个

class Program
{
    static void Main(string[] args)
    {
        if (RunWithTimeout(LongRunningOperation, TimeSpan.FromMilliseconds(3000)))
        {
            Console.WriteLine("Worker thread finished.");
        }
        else
        {
            Console.WriteLine("Worker thread was aborted.");
        }
    }

    static bool RunWithTimeout(ThreadStart threadStart, TimeSpan timeout)
    {
        Thread workerThread = new Thread(threadStart);

        workerThread.Start();

        bool finished = workerThread.Join(timeout);
        if (!finished)
            workerThread.Abort();

        return finished;
    }

    static void LongRunningOperation()
    {
        Thread.Sleep(5000);
    }
}

你可以看到it

【讨论】:

  • 需要注意的一点是,如果线程被阻塞(处于等待状态)(例如在套接字上等待),它在解除阻塞之前不会中止。而且我们无法控制它何时解除阻塞。
  • 这似乎是对的。根据问题,虽然可以在主线程中进行操作。就像启动计时器、执行 Thread.Abort() OnTimer 并捕获 ThreadAbortException 一样,感觉有些不对。
  • @zespri 不会在套接字上永远阻塞,设置套接字超时或使用套接字轮询超时,所有这些都在一个循环中。
  • @Eugene Ryabtsev 只是供 OP 考虑的事情
【解决方案3】:

在后台线程中进行计算并等待线程完成。要中止计算,请使用Thread.Abort(),这将在计算线程中抛出ThreadAbortException

【讨论】:

    【解决方案4】:

    如果您有一个用于引入检查和退出的代码点,您只能从同一线程中止长时间运行的进程。这是因为 - 显然 - 线程很忙,所以它不能处理检查以中止自己。因此,您的示例仅包含对“LongRunningMethod”的一次调用,无法从同一个线程中止。您需要显示更多代码才能获得指导。

    作为一般规则,长时间运行的任务最好发送到不同的线程(例如,通过 BackgroundWorker 或新线程),以便它们可以中止。

    这是一个简单的方法;

    private void StartThread()
    {
        Thread t = new Thread(LongRunningMethod);
        t.Start();
        if (!t.Join(10000)) // give the operation 10s to complete
        {
            // the thread did not complete on its own, so we will abort it now
            t.Abort();
        }
    }
    
    private void LongRunningMethod()
    {
        // do something that'll take awhile
    }
    

    【讨论】:

    • 如果我在调用StartThread()方法后还有一行代码,是不是要等10s才能运行?
    • 不,它只是给线程 10 秒的时间来完成,从您调用 .Join 的时间开始 - 如果线程已经完成,则不会有延迟。
    【解决方案5】:

    由于您无法控制该代码,我相信正确的方法是使用 WaitHandles 和 ThreadPool 运行该代码:

    WaitHandle waitHandle = new AutoResetEvent(false);
    ThreadPool.QueueUserWorkItem(new WaitCallback(<long running task delegate>), waitHandle);
    WaitHandle.WaitAll(new[]{ waitHandle }, <timeout>);
    

    Here 你可以找到更多关于 WaitHandle 工作原理的信息。

    【讨论】:

    • 这不会终止“长时间运行的进程”。
    • 正确。对于那个很抱歉。然后 Thread.Join() 加上一个 Abort,如其他答案所示,应该可以解决问题。 Here 是同一问题的其他有效解决方案。
    猜你喜欢
    • 2014-02-27
    • 2012-09-08
    • 1970-01-01
    • 2020-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-07
    • 2015-12-30
    相关资源
    最近更新 更多