2

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.

John Isaiah Carmona
  • 5,260
  • 10
  • 45
  • 79

5 Answers5

3

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

Community
  • 1
  • 1
Raab
  • 34,778
  • 4
  • 50
  • 65
  • One thing to note, that is if the thread is blocked (in the wait state) (for example waiting on a socket) it won't get aborted until it unblocks. And we don't have control when it unblocks. – Andrew Savinykh May 31 '12 at 05:50
  • That seems to be about right. While it MIGHT be possible to do in the main thread, as per the question. Like with starting a timer, doing Thread.Abort() OnTimer and catching that ThreadAbortException, that feels somehow wrong. – Eugene Ryabtsev May 31 '12 at 05:51
  • @zespri don't block forever on sockets, set socket timeouts or use socket poll with timeouts, all in a loop. – Eugene Ryabtsev May 31 '12 at 05:52
  • @Eugene Ryabtsev just something for the OP to consider – Andrew Savinykh May 31 '12 at 05:54
2

See my answer to this question for a generic solution.

Community
  • 1
  • 1
leppie
  • 115,091
  • 17
  • 196
  • 297
  • @JohnIsaiahCarmona: Probably, but I know not much about threading ;p There might be subtle differences. Reading up on it now. – leppie May 31 '12 at 05:59
  • What does the `while (t.ThreadState != ThreadState.Running)` line do? – John Isaiah Carmona May 31 '12 at 06:59
  • 1
    @JohnIsaiahCarmona: That just makes sure the thread has really started before starting the 'countdown'. Say a thread takes 20ms to start, and limit the timeout to say 10ms, the thread would not even have started. For longer timeouts, it is not needed. – leppie May 31 '12 at 07:24
  • Thanks, I use your code, but instead of `AutoResetEvent`, I use `Thread.Join`. Don't know if it has any difference. Thanks again for your help. :) – John Isaiah Carmona May 31 '12 at 07:34
1

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.

Carsten Schütte
  • 4,408
  • 1
  • 20
  • 24
1

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
}
RJ Lohan
  • 6,497
  • 3
  • 34
  • 54
  • if I have another line of code after calling the `StartThread()` method, would it wait for 10s to run it? – John Isaiah Carmona May 31 '12 at 06:12
  • No, it just gives the thread 10 seconds to complete, starting from the time you call .Join - if the thread is already complete, there will be no delay. – RJ Lohan May 31 '12 at 06:20
1

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.

Pablo Romeo
  • 11,298
  • 2
  • 30
  • 58
  • This wont terminate the 'long running process'. – leppie May 31 '12 at 05:55
  • Correct. Sorry about that. Then Thread.Join() plus an Abort, as shown in other answers should do the trick. [Here](http://stackoverflow.com/questions/299198/implement-c-sharp-generic-timeout) are other valid solutions to this same problem. – Pablo Romeo May 31 '12 at 06:06