1

I would like to do sth like this pseudo-code:

try for new Timespan(0,0,4) {
    // maximum execution time of this block: 4 seconds
    result = longRunningFunction(parameter);
    doSthWithResult(result);
    ...
} catch(TimeOutException) {
    Console.WriteLine("TimeOut occured");
}

Is such a construct available in C#, and if not, how would I implement a behaviour that allows trying to execute a function/block for a certain amount of time?

If that helps: I am searching for ASP.NET WebAPI (although I could use the timeout in a WinForms App as well).

Alexander
  • 19,906
  • 19
  • 75
  • 162
  • At least with winforms you would have a problem if you want to make sure that it does only execute for that span. The problem is you need multiple threads and even if you tell a child-thread to shutdown (kill the thread) there is no guarantee that the thread does stop until the application itself stops (it gets worse if its a background thread as that one can survive the end of the application). ASP.NET I don't know if it has a similar problem or not. Winforms sadly has that problem – Thomas Dec 09 '14 at 12:22
  • 1
    Depends upon what that `longRunningFunction` does. You need to support cancellation in that method. – Sriram Sakthivel Dec 09 '14 at 12:23
  • http://stackoverflow.com/questions/4238345/asynchronously-wait-for-taskt-to-complete-with-timeout – Emil Lundin Dec 09 '14 at 12:23
  • @SriramSakthivel even if he has support for it problem is that if he needs to make sure taht it stops at exactly that time....then its not possible in winforms as there is no guarantee that it really stops at that millisecond (it stops only when the cancellation token is checked which can be at that millisecond or seconds later or never depending on the implementation, luck and possible errors). so the mainquestion is: is it necessary that the timeout is a hard timeout or is it more meant "stop beginning here" Alexander ? – Thomas Dec 09 '14 at 12:29
  • 1
    @Thomas Yes you're right. There is no guarantee that cancellation will be responded immediately. So, yes you can't say it must time out strictly in given time. Or something like `Task.WhenAny` could be useful ignoring the `longRunningFunction` after timed out. Another evil and unreliable option is `Thread.Abort`, I don't recommend it but you can(won't work always). – Sriram Sakthivel Dec 09 '14 at 12:35
  • I have been there and I have to say even when it works it has the same problem that it is no guarantee taht it can cancel on exactly that millisceond sadly. So @Alexander how hard is the timeout? Does the longrunningfunction need to stop right away at that millisecond (if so then sadly no way I know of that it is possible in winforms) or is it a soft timeout so that it can stop after a while later (be it a few milliseconds or seconds depending on when the cancel-token is reached)? – Thomas Dec 09 '14 at 12:38
  • It's more or less telling the function: "I won't wait for you any longer, and because you are not yet finished, I will proceed in a 'catch block'". – Alexander Dec 09 '14 at 12:38
  • Ah ok so a soft timeout in essence. That is possible in winforms (quite easy even). ASP.NET I sadly dont know if possible/how best possible. Is it then necessary to tell the subfunction that it can abort/cancel at all (currently thinking already of how to do the winforms code example)? – Thomas Dec 09 '14 at 12:46

1 Answers1

2

If you want the longRunningFunction() itself to stop, then you need to implement logic in that method to do so. How to do that depends on the exact implementation of the method, which you haven't provided, so that would be unanswerable given your current question.

However, in many cases it's sufficient to simply abandon an operation, letting it run to completion on its own but simply ignoring the result. You might call that "getting on with your life". :)

If that's the case here, then something like this should work for you:

Task<T> resultTask = Task.Run(() => longRunningFunction(parameter));

// maximum execution time of this block: 4 seconds
await Task.WhenAny(resultTask, Task.Delay(4000));

if (resultTask.IsCompleted)
{
    doSthWithResult(resultTask.Result);
}
else
{
    Console.WriteLine("TimeOut occurred");
}

Replace T in the resultTask declaration with whatever the actual return type for longRunningFunction() is.

Note that the above is opportunistic, in that even if the long-running operation takes longer than 4 seconds and the Task.Delay(4000) wins the race, as long as it completes by the time your code gets back to the if (resultTask.IsCompleted check, it will still be considered a success. If you want to give it a strict cut-off, ignoring the result if the Task.Delay(4000) completes first even if the operation finishes by the time you actually check which finished first, you can do that by looking at which task finished first:

Task winner = await Task.WhenAny(resultTask, Task.Delay(4000));

if (resultTask == winner)
{
    doSthWithResult(resultTask.Result);
}
else
...

Finally: even if you do need the longRunningFunction() to stop, you can use the above technique and then interrupt the operation in the else clause where you report the time-out (via whatever mechanism is appropriate in your case…again, without the actual code it's not possible to say exactly what that would be).

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136