How to abort a long running method?

2019-03-01 13:39发布

问题:

I have a long running method and I want to add timeout into it. Is it feasible to do that? Something like:

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

Where when it reached 20 seconds, the method will be aborted. The method doesn't have loop and I do not have a control/code over that method.

回答1:

See my answer to this question for a generic solution.



回答2:

try this

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

you can see it



回答3:

Do the calculation in a background thread and wait until the thread finishes. To abort calculation, use Thread.Abort(), this will throw a ThreadAbortException in the calculation thread.



回答4:

You can only abort long running process from the same thread if you have a code point in which to introduce a check and exit. This is because - clearly - the thread is busy, so it can't process checks to abort itself. So, your example which only contains one call to 'LongRunningMethod' could not be aborted from the same thread. You'd need to show more code in order to get direction on that.

As a general rule, long-running tasks are best sent to different threads (e.g; via a BackgroundWorker or new Thread) so they can be aborted.

Here is a simple way to do this;

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
}


回答5:

Since you have no control over that code I believe the correct approach would be to run that code using WaitHandles and the ThreadPool:

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

Here you can find more info on how WaitHandle works.