71

Possible Duplicate:
Set timeout to an operation

How can i set timeout for a line of code in c#. For example RunThisLine(SomeMethod(Some Input), TimeSpan.FromSeconds(10)) run SomeMethod with 10 second time out. Thanks in advance.

Community
  • 1
  • 1
Hossein
  • 933
  • 2
  • 9
  • 21

3 Answers3

159

You can use the Task Parallel Library. To be more exact, you can use Task.Wait(TimeSpan):

using System.Threading.Tasks;

var task = Task.Run(() => SomeMethod(input));
if (task.Wait(TimeSpan.FromSeconds(10)))
    return task.Result;
else
    throw new Exception("Timed out");
Colonel Panic
  • 132,665
  • 89
  • 401
  • 465
Carsten
  • 11,287
  • 7
  • 39
  • 62
  • 6
    It's great. The result of `SomeMethod` will be in `task.Result` variable. Thanks. – Hossein Nov 26 '12 at 05:16
  • 6
    It's not necessary to use the `CancellationToken` if you just need timeout, and/or your method does not handle the token on cancelation. Wait has an overload without `token` that works just fine. – trapicki Nov 19 '14 at 10:13
  • Take care guys, this _might_ change the behaviour of the app (as in my case) – oo_dev Jun 28 '16 at 10:21
  • 3
    this is good solution but, this is not stop function. only notify about timeout. – Bondaryuk Vladimir Nov 17 '16 at 09:56
  • @BondaryukVladimir: Yep, just as the documentation for `Task.Wait` states. If [task cancellation](https://msdn.microsoft.com/de-de/library/dd997396(v=vs.110).aspx) is required, you have to use `CancellationToken`s and handle them from within your task. Do not utilize the deprecated `Thread.Abort`-method! I've had a sample to this included earlier, but simplified it due to comments to this answer. I will edit it, in order to demonstrate how to use it, if that's whats causing confusion. – Carsten Nov 17 '16 at 11:58
  • @Carsten Is it possible to have SomeMethod is some InterOP(COM) Method – ChiragMM Jan 09 '18 at 18:43
  • @ChiragMM Sure it is, because interop libraries are also just .NET assemblies! However, you have to make sure the COM library behind your interop does support multithreading. If the called object is in an STA, then the Marhsaller will take care of syncing your requests. Otherwise the object itself needs to synchronize parallel calls, if required. But that's not a requirement of the calling code (i.e. if you call your COM objects from multiple C++ threads, you would have to do the same). – Carsten Jan 12 '18 at 13:55
  • 1
    @trapicki This really depends. As `Wait` won't end the thread that executes `SomeMethod`, if you have a listener in SomeMethod, it will still listen instead of cancel out. It can also consume unecessary resource after timeout. – joe Mar 27 '19 at 01:51
  • 3
    The snippet will still wait for 10s, even if SomeMethod responds in 2s. – Valerian Pereira Jun 15 '19 at 09:34
  • 6
    @ValerianPereira: It shouldn't, according to [MSDN](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.wait?view=netframework-4.8#System_Threading_Tasks_Task_Wait_System_TimeSpan_) (see Remarks), it blocks until a) *the task completes successfully*, b) the task throws an exception or c) the task times out. – Carsten Jun 22 '19 at 12:41
  • Rather than running `SomeMethod` on a separate thread (which might be troublesome in some applications - eg if `SomeMethod` has to access the UI thread), you could alternatively put your timeout on a separate thread like this: https://gist.github.com/derekantrican/dd358184c3ea8d26ba1cef70d31dda36 – derekantrican Jul 28 '20 at 03:24
  • 1
    @derekantrican: Indeed this can be an option. However, instead of `System.Threading`, it should also be implemented using TPL (and [cooperative cancellation](https://learn.microsoft.com/en-us/dotnet/standard/threading/destroying-threads)) for newer Framework versions. Otherwise it is not compatible with .NET Core, since it calls `Thread.Abort` if the code does not time-out. In that case, you receive a `PlatformNotSupportedException`. – Carsten Jul 28 '20 at 09:13
16

You can use the IAsyncResult and Action class/interface to achieve this.

public void TimeoutExample()
{
    IAsyncResult result;
    Action action = () =>
    {
        // Your code here
    };

    result = action.BeginInvoke(null, null);

    if (result.AsyncWaitHandle.WaitOne(10000))
         Console.WriteLine("Method successful.");
    else
         Console.WriteLine("Method timed out.");
}
Mo Patel
  • 2,321
  • 4
  • 22
  • 37
7

I use something like this (you should add code to deal with the various fails):

    var response = RunTaskWithTimeout<ReturnType>(
        (Func<ReturnType>)delegate { return SomeMethod(someInput); }, 30);


    /// <summary>
    /// Generic method to run a task on a background thread with a specific timeout, if the task fails,
    /// notifies a user
    /// </summary>
    /// <typeparam name="T">Return type of function</typeparam>
    /// <param name="TaskAction">Function delegate for task to perform</param>
    /// <param name="TimeoutSeconds">Time to allow before task times out</param>
    /// <returns></returns>
    private T RunTaskWithTimeout<T>(Func<T> TaskAction, int TimeoutSeconds)
    {
        Task<T> backgroundTask;

        try
        {
            backgroundTask = Task.Factory.StartNew(TaskAction);
            backgroundTask.Wait(new TimeSpan(0, 0, TimeoutSeconds));
        }
        catch (AggregateException ex)
        {
            // task failed
            var failMessage = ex.Flatten().InnerException.Message);
            return default(T);
        }
        catch (Exception ex)
        {
            // task failed
            var failMessage = ex.Message;
            return default(T);
        }

        if (!backgroundTask.IsCompleted)
        {
            // task timed out
            return default(T);
        }

        // task succeeded
        return backgroundTask.Result;
    }
paul
  • 21,653
  • 1
  • 53
  • 54