Cancelling a Task is throwing an exception - c#

From what I've read about Tasks, the following code should cancel the currently executing task without throwing an exception. I was under the impression that the whole point of task cancellation was to politely "ask" the task to stop without aborting threads.
The output from the following program is:
Dumping exception
[OperationCanceledException]
Cancelling and returning last calculated prime.
I am trying to avoid any exceptions when cancelling. How can I accomplish this?
void Main()
{
var cancellationToken = new CancellationTokenSource();
var task = new Task<int>(() => {
return CalculatePrime(cancellationToken.Token, 10000);
}, cancellationToken.Token);
try
{
task.Start();
Thread.Sleep(100);
cancellationToken.Cancel();
task.Wait(cancellationToken.Token);
}
catch (Exception e)
{
Console.WriteLine("Dumping exception");
e.Dump();
}
}
int CalculatePrime(CancellationToken cancelToken, object digits)
{
int factor;
int lastPrime = 0;
int c = (int)digits;
for (int num = 2; num < c; num++)
{
bool isprime = true;
factor = 0;
if (cancelToken.IsCancellationRequested)
{
Console.WriteLine ("Cancelling and returning last calculated prime.");
//cancelToken.ThrowIfCancellationRequested();
return lastPrime;
}
// see if num is evenly divisible
for (int i = 2; i <= num/2; i++)
{
if ((num % i) == 0)
{
// num is evenly divisible -- not prime
isprime = false;
factor = i;
}
}
if (isprime)
{
lastPrime = num;
}
}
return lastPrime;
}

I am trying to avoid any exceptions when cancelling.
You shouldn't do that.
Throwing OperationCanceledException is the idiomatic way that "the method you called was cancelled" is expressed in TPL. Don't fight against that - just expect it.
It's a good thing, because it means that when you've got multiple operations using the same cancellation token, you don't need to pepper your code at every level with checks to see whether or not the method you've just called has actually completed normally or whether it's returned due to cancellation. You could use CancellationToken.IsCancellationRequested everywhere, but it'll make your code a lot less elegant in the long run.
Note that there are two pieces of code in your example which are throwing an exception - one within the task itself:
cancelToken.ThrowIfCancellationRequested()
and one where you wait for the task to complete:
task.Wait(cancellationToken.Token);
I don't think you really want to be passing the cancellation token into the task.Wait call, to be honest... that allows other code to cancel your waiting. Given that you know you've just cancelled that token, it's pointless - it's bound to throw an exception, whether the task has actually noticed the cancellation yet or not. Options:
Use a different cancellation token (so that other code can cancel your wait independently)
Use a time-out
Just wait for as long as it takes

You are explicitly throwing an Exception on this line:
cancelToken.ThrowIfCancellationRequested();
If you want to gracefully exit the task, then you simply need to get rid of that line.
Typically people use this as a control mechanism to ensure the current processing gets aborted without potentially running any extra code. Also, there is no need to check for cancellation when calling ThrowIfCancellationRequested() since it is functionally equivalent to:
if (token.IsCancellationRequested)
throw new OperationCanceledException(token);
When using ThrowIfCancellationRequested() your Task might look more like this:
int CalculatePrime(CancellationToken cancelToken, object digits) {
try{
while(true){
cancelToken.ThrowIfCancellationRequested();
//Long operation here...
}
}
finally{
//Do some cleanup
}
}
Also, Task.Wait(CancellationToken) will throw an exception if the token was cancelled. To use this method, you will need to wrap your Wait call in a Try...Catch block.
MSDN: How to Cancel a Task

Some of the above answers read as if ThrowIfCancellationRequested() would be an option. It is not in this case, because you won't get your resulting last prime. The idiomatic way that "the method you called was cancelled" is defined for cases when canceling means throwing away any (intermediate) results. If your definition of cancelling is "stop computation and return the last intermediate result" you already left that way.
Discussing the benefits especially in terms of runtime is also quite misleading:
The implemented algorithm sucks at runtime. Even a highly optimized cancellation will not do any good.
The easiest optimization would be to unroll this loop and skip some unneccessary cycles:
for(i=2; i <= num/2; i++) {
if((num % i) == 0) {
// num is evenly divisible -- not prime
isprime = false;
factor = i;
}
}
You can
save (num/2)-1 cycles for every even number, which is slightly less than 50% overall (unrolling),
save (num/2)-square_root_of(num) cycles for every prime (choose bound according to math of smallest prime factor),
save at least that much for every non-prime, expect much more savings, e.g. num = 999 finishes with 1 cycle instead of 499 (break, if answer is found) and
save another 50% of cycles, which is of course 25% overall (choose step according to math of primes, unrolling handles the special case 2).
That accounts to saving a guaranteed minimum of 75% (rough estimation: 90%) of cycles in the inner loop, just by replacing it with:
if ((num % 2) == 0) {
isprime = false;
factor = 2;
} else {
for(i=3; i <= (int)Math.sqrt(num); i+=2) {
if((num % i) == 0) {
// num is evenly divisible -- not prime
isprime = false;
factor = i;
break;
}
}
}
There are much faster algorithms (which I won't discuss because I'm far enough off-topic) but this optimization is quite easy and still proves my point:
Don't worry about micro-optimizing runtime when your algorithm is this far from optimal.

Another note about the benefit of using ThrowIfCancellationRequested rather than IsCancellationRequested: I've found that when needing to use ContinueWith with a continuation option of TaskContinuationOptions.OnlyOnCanceled, IsCancellationRequested will not cause the conditioned ContinueWith to fire. ThrowIfCancellationRequested, however, will set the Canceled condition of the task, causing the ContinueWith to fire.
Note: This is only true when the task is already running and not when the task is starting. This is why I added a Thread.Sleep() between the start and cancellation.
CancellationTokenSource cts = new CancellationTokenSource();
Task task1 = new Task(() => {
while(true){
if(cts.Token.IsCancellationRequested)
break;
}
}, cts.Token);
task1.ContinueWith((ant) => {
// Perform task1 post-cancellation logic.
// This will NOT fire when calling cst.Cancel().
}
Task task2 = new Task(() => {
while(true){
cts.Token.ThrowIfCancellationRequested();
}
}, cts.Token);
task2.ContinueWith((ant) => {
// Perform task2 post-cancellation logic.
// This will fire when calling cst.Cancel().
}
task1.Start();
task2.Start();
Thread.Sleep(3000);
cts.Cancel();

You have two things listening to the token, the calculate prime method and also the Task instance named task. The calculate prime method should return gracefully, but task gets cancelled while it is still running so it throws. When you construct task don't bother giving it the token.

Related

Is the correct way to cancel a cancellation token used in a task?

I have code that creates a cancellation token
public partial class CardsTabViewModel : BaseViewModel
{
public CancellationTokenSource cts;
public async Task OnAppearing()
{
cts = new CancellationTokenSource(); // << runs as part of OnAppearing()
Code that uses it:
await GetCards(cts.Token);
public async Task GetCards(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
App.viewablePhrases = App.DB.GetViewablePhrases(Settings.Mode, Settings.Pts);
await CheckAvailability();
}
}
and code that later cancels this Cancellation Token if the user moves away from the screen where the code above is running:
public void OnDisappearing()
{
cts.Cancel();
Regarding cancellation, is this the correct way to cancel the token when it's being used in a Task?
In particular I checked this question:
Use of IsCancellationRequested property?
and it's making me think that I am not doing the cancel the correct way or perhaps in a way that can cause an exception.
Also, in this case after I have cancelled then should I be doing a cts.Dispose()?
In general I see a fair use of Cancel Token in your code, but according the Task Async Pattern your code could be not cancelling immediately.
while (!ct.IsCancellationRequested)
{
App.viewablePhrases = App.DB.GetViewablePhrases(Settings.Mode, Settings.Pts);
await CheckAvailability(); //Your Code could be blocked here, unable to cancel
}
For responding right away, the blocking code also should be cancelled
await CheckAvailability(ct); //Your blocking code in the loop also should be stoped
It is up to you if you must Dispose, if there are many memory resources been reserved in the interrupted code, you should do it.
CancellationTokenSource.Cancel() is a valid way to start cancellation.
Polling ct.IsCancellationRequested avoids throwing OperationCanceledException.
Because its polling, it requires an iteration of the loop to complete before it will respond to the cancellation request.
If GetViewablePhrases() and CheckAvailability() can be modified to accept a CancellationToken, this may make cancellation faster to respond, at the cost of having OperationCanceledException thrown.
"should I be doing a cts.Dispose()?" is not that straightforward...
"Always dispose IDisposables ASAP"
Is more of a guideline than a rule.
Task itself is disposable, yet hardly ever directly disposed in code.
There are cases (when WaitHandle or cancellation callback handlers are used) where disposing cts would free a resource / remove a GC root which otherwise would only be freed by a Finalizer.
These don't apply to your code as it stands but may in future.
Adding a call to Dispose after cancelling would guarantee that these resources are freed promptly in future versions of the code.
However, you'd have to either wait for the code that uses cts to finish before calling dispose, or modify the code to deal with ObjectDisposedException from use of cts (or its token) after disposal.
I would recommend you to take a look on one of the .net classes to fully understand how to handle wait methods with CanncelationToken, I picked up SeamaphoreSlim.cs
public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
{
CheckDispose();
// Validate input
if (millisecondsTimeout < -1)
{
throw new ArgumentOutOfRangeException(
"totalMilliSeconds", millisecondsTimeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
}
cancellationToken.ThrowIfCancellationRequested();
uint startTime = 0;
if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout > 0)
{
startTime = TimeoutHelper.GetTime();
}
bool waitSuccessful = false;
Task<bool> asyncWaitTask = null;
bool lockTaken = false;
//Register for cancellation outside of the main lock.
//NOTE: Register/deregister inside the lock can deadlock as different lock acquisition orders could
// occur for (1)this.m_lockObj and (2)cts.internalLock
CancellationTokenRegistration cancellationTokenRegistration = cancellationToken.InternalRegisterWithoutEC(s_cancellationTokenCanceledEventHandler, this);
try
{
// Perf: first spin wait for the count to be positive, but only up to the first planned yield.
// This additional amount of spinwaiting in addition
// to Monitor.Enter()’s spinwaiting has shown measurable perf gains in test scenarios.
//
SpinWait spin = new SpinWait();
while (m_currentCount == 0 && !spin.NextSpinWillYield)
{
spin.SpinOnce();
}
// entering the lock and incrementing waiters must not suffer a thread-abort, else we cannot
// clean up m_waitCount correctly, which may lead to deadlock due to non-woken waiters.
try { }
finally
{
Monitor.Enter(m_lockObj, ref lockTaken);
if (lockTaken)
{
m_waitCount++;
}
}
// If there are any async waiters, for fairness we'll get in line behind
// then by translating our synchronous wait into an asynchronous one that we
// then block on (once we've released the lock).
if (m_asyncHead != null)
{
Contract.Assert(m_asyncTail != null, "tail should not be null if head isn't");
asyncWaitTask = WaitAsync(millisecondsTimeout, cancellationToken);
}
// There are no async waiters, so we can proceed with normal synchronous waiting.
else
{
// If the count > 0 we are good to move on.
// If not, then wait if we were given allowed some wait duration
OperationCanceledException oce = null;
if (m_currentCount == 0)
{
if (millisecondsTimeout == 0)
{
return false;
}
// Prepare for the main wait...
// wait until the count become greater than zero or the timeout is expired
try
{
waitSuccessful = WaitUntilCountOrTimeout(millisecondsTimeout, startTime, cancellationToken);
}
catch (OperationCanceledException e) { oce = e; }
}
// Now try to acquire. We prioritize acquisition over cancellation/timeout so that we don't
// lose any counts when there are asynchronous waiters in the mix. Asynchronous waiters
// defer to synchronous waiters in priority, which means that if it's possible an asynchronous
// waiter didn't get released because a synchronous waiter was present, we need to ensure
// that synchronous waiter succeeds so that they have a chance to release.
Contract.Assert(!waitSuccessful || m_currentCount > 0,
"If the wait was successful, there should be count available.");
if (m_currentCount > 0)
{
waitSuccessful = true;
m_currentCount--;
}
else if (oce != null)
{
throw oce;
}
// Exposing wait handle which is lazily initialized if needed
if (m_waitHandle != null && m_currentCount == 0)
{
m_waitHandle.Reset();
}
}
}
finally
{
// Release the lock
if (lockTaken)
{
m_waitCount--;
Monitor.Exit(m_lockObj);
}
// Unregister the cancellation callback.
cancellationTokenRegistration.Dispose();
}
// If we had to fall back to asynchronous waiting, block on it
// here now that we've released the lock, and return its
// result when available. Otherwise, this was a synchronous
// wait, and whether we successfully acquired the semaphore is
// stored in waitSuccessful.
return (asyncWaitTask != null) ? asyncWaitTask.GetAwaiter().GetResult() : waitSuccessful;
}
You can also view the whole class here, https://referencesource.microsoft.com/#mscorlib/system/threading/SemaphoreSlim.cs,6095d9030263f169

Another way to cancel Task

I have a simple console application
class Program
{
private static void MyTask(object obj)
{
var cancellationToken = (CancellationToken) obj;
if(cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
Console.WriteLine("MyTask() started");
for (var i = 0; i < 10; i++)
{
try
{
if (cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
}
catch (Exception ex)
{
return;
}
Console.WriteLine($"Counter in MyTask() = {i}");
Thread.Sleep(500);
}
Console.WriteLine("MyTask() finished");
}
static void Main(string[] args)
{
var cancelationTokenSource = new CancellationTokenSource();
var task = Task.Factory.StartNew(MyTask, cancelationTokenSource.Token,
cancelationTokenSource.Token);
Thread.Sleep(3000);
try
{
cancelationTokenSource.Cancel();
task.Wait();
}
catch (Exception ex)
{
if(task.IsCanceled)
Console.WriteLine("Task has been cancelled");
Console.WriteLine(ex.Message);
}
finally
{
cancelationTokenSource.Dispose();
task.Dispose();
}
Console.WriteLine("Main finished");
Console.ReadLine();
}
}
I'm trying to start new Task and after some time cancel it. Is there any other way to achieve this result instead of using this
if(cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
on every iteration in for loop? Why do we have to check cancellationToken.IsCancellationRequested on every iteration, maybe we can to use something else?
In this specific case you could avoid the .ThrowIfCancellationRequested(), and instead simply use a break to stop the execution of the loop and then finish the Task. The ThrowIfCancellationRequested is more useful in deeper task trees, where there are many more descendants and it is more difficult to maintain cancellation.
if (cancellationToken.IsCancellationRequested)
{
break;
}
Stephen Toub has a good explanation on how the throwing of the OCE is more of an acknowledgement.
If the body of the task is also monitoring the cancellation token and throws an OperationCanceledException containing that token (which is what ThrowIfCancellationRequested does), then when the task sees that OCE, it checks whether the OCE's token matches the Task's token. If it does, that exception is viewed as an acknowledgement of cooperative cancellation and the Task transitions to the Canceled state (rather than the Faulted state).
Not sure what your objection to checking on every iteration is, but if you do not want to check on every iteration, for whatever reason, check the value of i:
E.g. this checks every 10th loop:
if (i % 10 == 0 && cancellationToken.IsCancellationRequested)
The reason you must check is so that you can decide where is best to stop the task so that work is not left in an inconsistent state. Here though all you will achieve by checking less frequently is a task that is slower to cancel, maybe that will lead to a less responsive UX. E.g. where the task would end in 500ms before, now it can take up to 10x that, 5 secs.
However if each loop was very fast, and checking the flag every loop proves to significantly increase the overall time the task takes, then checking every n loops makes sence.

Cancel execution of command if it takes too long

I am currently working on a piece of software that uses an assembly from a different department.I call a Method from this assembly like this:
using (var connection = (IConnection) Factory.GetObject(typeof (IConnection)))
The code used to work perfectly fine. But for the last few minutes it seemed like my program was doing nothing when I tried to launch it. Pressing pause while debugging showed me it got "stuck" at the line above.My guess is they're just doing some maintenance or something but that's not the point here.
So I though it would be nice to tell the user what went wrong if the program doesn't start. Something simple like
MessageBox.Show("Could not connect", "Connection Error");
And then close the program. My question is:
How do I terminate the execution of a command after a set amount of time and jump somewhere else?My guess would be moving it to a separate thread and then putting the calling thread to sleep for a few seconds after which it disposes of the extra thread if it isn't completed yet. But that seems really dirty to me and there's got to be a better way.
Your question can be separated into two parts:
How to terminate the execution of a command?
The only way is to abort the thread. But don't do it. There is no guaranteed and safe way. There are such methods like Thread.Interrupt and Thread.Abort that can wake up the thread. But they will work only if the thread is in the WaitSleepJoin state and it hangs in managed code.
Seems like you already know it. But once again, if something inside the assembly hangs infinitely the execution of code then the thread is probably "gone". So you are right that the program should be closed.
... jump somewhere else?
Good approach is using of TPL and async model.
Here is an extension method to wrap up any Task and expires after timeout.
public static async Task TimeoutAfter(this Task task, int millisecondsTimeout)
{
if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout)))
await task;
else
throw new TimeoutException();
}
Then use it
try
{
using (var result = await Task.Run(() => (IConnection)Factory.GetObject(typeof(IConnection))).TimeoutAfter(1000))
{
...
}
}
catch (TimeoutException ex)
{
//timeout
}
Here you can find more information
A simple way of doing it without extra libraries or extension methods:
using ( var task = new Task<IConnection>( () => Factory.GetObject( typeof( IConnection ) ) ) )
{
task.Start();
if( !task.Wait( timeoutMilliseconds ) )
{
throw new TimeoutException();
}
IConnection result = task.Result;
}
Task.Wait does what you want, because you can throw an exception if it returns false (task didn't complete in time.)
It's even simpler if you have an Action that doesn't return something:
if ( !Task.Run( action ).Wait( timeoutMilliseconds ) )
{
throw new TimeoutException();
}
Where action is some Action or lambda.
The easiest way to do this, if a native timeout is not implemented, as you mentioned, is a separate thread to load it on. Although this sounds like it'll be really dirty, it's as simple as (using Rx):
Task<IConnection> connectionTask = Observable.Start(() => Factory.GetObject(typeof (IConnection)), Scheduler.Default).Timeout(TimeSpan.FromSeconds(20)).ToTask());
using (var connection = connectionTask.Result)
{
...
}
You can tweak the Scheduler if you don't want it to run on the threadpool. It will throw a TimeoutException if the Factory.GetObject call takes longer than 20 seconds.
You could use CancellationTokenSource to set a timeout on the operation
var timeoutCts = new CancellationTokenSource();
try
{
timeoutCts.CancelAfter(300000); // Cancel after 5 minutes
// ... run your long term operation
}
catch (OperationCanceledException ex)
{
// Handle the timeout
}
Please see this documentation from Microsoft
using System;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
Task t = Task.Run(() =>
{
Random rnd = new Random();
long sum = 0;
int n = 5000000;
for (int ctr = 1; ctr <= n; ctr++)
{
int number = rnd.Next(0, 101);
sum += number;
}
Console.WriteLine("Total: {0:N0}", sum);
Console.WriteLine("Mean: {0:N2}", sum / n);
Console.WriteLine("N: {0:N0}", n);
});
TimeSpan ts = TimeSpan.FromMilliseconds(150);
if (!t.Wait(ts))
Console.WriteLine("The timeout interval elapsed.");
}
}

Async and Await - How is order of execution maintained?

I am actually reading some topics about the Task Parallel Library and the asynchronous programming with async and await. The book "C# 5.0 in a Nutshell" states that when awaiting an expression using the await keyword, the compiler transforms the code into something like this:
var awaiter = expression.GetAwaiter();
awaiter.OnCompleted (() =>
{
var result = awaiter.GetResult();
Let's assume, we have this asynchronous function (also from the referred book):
async Task DisplayPrimeCounts()
{
for (int i = 0; i < 10; i++)
Console.WriteLine (await GetPrimesCountAsync (i*1000000 + 2, 1000000) +
" primes between " + (i*1000000) + " and " + ((i+1)*1000000-1));
Console.WriteLine ("Done!");
}
The call of the 'GetPrimesCountAsync' method will be enqueued and executed on a pooled thread. In general invoking multiple threads from within a for loop has the potential for introducing race conditions.
So how does the CLR ensure that the requests will be processed in the order they were made? I doubt that the compiler simply transforms the code into the above manner, since this would decouple the 'GetPrimesCountAsync' method from the for loop.
Just for the sake of simplicity, I'm going to replace your example with one that's slightly simpler, but has all of the same meaningful properties:
async Task DisplayPrimeCounts()
{
for (int i = 0; i < 10; i++)
{
var value = await SomeExpensiveComputation(i);
Console.WriteLine(value);
}
Console.WriteLine("Done!");
}
The ordering is all maintained because of the definition of your code. Let's imagine stepping through it.
This method is first called
The first line of code is the for loop, so i is initialized.
The loop check passes, so we go to the body of the loop.
SomeExpensiveComputation is called. It should return a Task<T> very quickly, but the work that it'd doing will keep going on in the background.
The rest of the method is added as a continuation to the returned task; it will continue executing when that task finishes.
After the task returned from SomeExpensiveComputation finishes, we store the result in value.
value is printed to the console.
GOTO 3; note that the existing expensive operation has already finished before we get to step 4 for the second time and start the next one.
As far as how the C# compiler actually accomplishes step 5, it does so by creating a state machine. Basically every time there is an await there's a label indicating where it left off, and at the start of the method (or after it's resumed after any continuation fires) it checks the current state, and does a goto to the spot where it left off. It also needs to hoist all local variables into fields of a new class so that the state of those local variables is maintained.
Now this transformation isn't actually done in C# code, it's done in IL, but this is sort of the morale equivalent of the code I showed above in a state machine. Note that this isn't valid C# (you cannot goto into a a for loop like this, but that restriction doesn't apply to the IL code that is actually used. There are also going to be differences between this and what C# actually does, but is should give you a basic idea of what's going on here:
internal class Foo
{
public int i;
public long value;
private int state = 0;
private Task<int> task;
int result0;
public Task Bar()
{
var tcs = new TaskCompletionSource<object>();
Action continuation = null;
continuation = () =>
{
try
{
if (state == 1)
{
goto state1;
}
for (i = 0; i < 10; i++)
{
Task<int> task = SomeExpensiveComputation(i);
var awaiter = task.GetAwaiter();
if (!awaiter.IsCompleted)
{
awaiter.OnCompleted(() =>
{
result0 = awaiter.GetResult();
continuation();
});
state = 1;
return;
}
else
{
result0 = awaiter.GetResult();
}
state1:
Console.WriteLine(value);
}
Console.WriteLine("Done!");
tcs.SetResult(true);
}
catch (Exception e)
{
tcs.SetException(e);
}
};
continuation();
}
}
Note that I've ignored task cancellation for the sake of this example, I've ignored the whole concept of capturing the current synchronization context, there's a bit more going on with error handling, etc. Don't consider this a complete implementation.
The call of the 'GetPrimesCountAsync' method will be enqueued and executed on a pooled thread.
No. await does not initiate any kind of background processing. It waits for existing processing to complete. It is up to GetPrimesCountAsync to do that (e.g. using Task.Run). It's more clear this way:
var myRunningTask = GetPrimesCountAsync();
await myRunningTask;
The loop only continues when the awaited task has completed. There is never more than one task outstanding.
So how does the CLR ensure that the requests will be processed in the order they were made?
The CLR is not involved.
I doubt that the compiler simply transforms the code into the above manner, since this would decouple the 'GetPrimesCountAsync' method from the for loop.
The transform that you shows is basically right but notice that the next loop iteration is not started right away but in the callback. That's what serializes execution.

How to limit the execution time of a function in c sharp?

I've got a problem. I'm writing a benchmark and I have a function than is either done in 2 seconds or after ~5 minutes(depending on the input data). And I would like to stop that function if it's executed for more than 3 seconds...
How can I do it?
Thanks a lot!
Well..., I had the same question, and after reading all the answers here and the referred blogs, I settled for this,
It Lets me execute any block of code with a time limit, Declare the wrapper method
public static bool ExecuteWithTimeLimit(TimeSpan timeSpan, Action codeBlock)
{
try
{
Task task = Task.Factory.StartNew(() => codeBlock());
task.Wait(timeSpan);
return task.IsCompleted;
}
catch (AggregateException ae)
{
throw ae.InnerExceptions[0];
}
}
And use that to wrap any block of code like this
// code here
bool Completed = ExecuteWithTimeLimit(TimeSpan.FromMilliseconds(1000), () =>
{
//
// Write your time bounded code here
//
});
//More code
The best way would be that your function can check its execution time often enough to decide to stop it it takes too long.
If this is not the case, then run the function in a separate thread. In your main thread start a 3 seconds timer. When timer elapses, kill the separate thread using Thread.Abort() (of course unless the function is already over). See sample code and preacuations of usage in the function docs.
The best way in C# to stop function in middle is the return keyword in function, but how do I know when to use the return keyword to stop the function in middle, after it lasts at least 3 seconds? The Stopwatch class from System.Diagnostics is the answer. This complicated function that lasts between 2 seconds to 5 minutes (depending on the input data) logically uses many loops, and maybe even recursion, so my solution for you is that, at the first line code of that function, create an instance of Stopwatch using System.Diagnostics with the new keyword, start it by calling the Start() function of the Stopwatch class, and in for each loop and loop, at the beginning, add the following code:
if (stopwatch.ElapsedMilliseconds >= 3000) {
stopwatch.Stop();
// or
stopwatch.Reset();
return;
}
(tip: you can type it with hands once, copy it Ctrl+C, and then just paste it Ctrl+V). If that function uses recursion, in order to save memory, make the Stopwatch global instance rather than creating it as local instance at first, and start it if it does not running at the beginning of the code. You can know that with the IsRunning of the Stopwatch class. After that ask if elapsed time is more than 3 seconds, and if yes (true) stop or reset the Stopwatch, and use the return keyword to stop the recursion loop, very good start in function, if your function lasts long time due mainly recursion more than loops. That it is. As you can see, it is very simple, and I tested this solution, and the results showed that it works! Try it yourself!
private static int LongRunningMethod()
{
var r = new Random();
var randomNumber = r.Next(1, 10);
var delayInMilliseconds = randomNumber * 1000;
Task.Delay(delayInMilliseconds).Wait();
return randomNumber;
}
And
var task = Task.Run(() =>
{
return LongRunningMethod();
});
bool isCompletedSuccessfully = task.Wait(TimeSpan.FromMilliseconds(3000));
if (isCompletedSuccessfully)
{
return task.Result;
}
else
{
throw new TimeoutException("The function has taken longer than the maximum time allowed.");
}
it work for me!
Source: https://jeremylindsayni.wordpress.com/2016/05/28/how-to-set-a-maximum-time-to-allow-a-c-function-to-run-for/
You can use the fork/join pattern, in the Task Parallel Library this is implemented with Task.WaitAll()
using System.Threading.Tasks;
void CutoffAfterThreeSeconds() {
// start function on seperate thread
CancellationTokenSource cts = new CancellationTokenSource();
Task loop = Task.Factory.StartNew(() => Loop(cts.Token));
// wait for max 3 seconds
if(Task.WaitAll(new Task[]{loop}, 3000)){
// Loop finished withion 3 seconds
} else {
// it did not finish within 3 seconds
cts.Cancel();
}
}
// this one takes forever
void Loop() {
while (!ct.IsCancellationRequested) {
// your loop goes here
}
Console.WriteLine("Got Cancelled");
}
This will start the other task on a seperate thread, and then wait for 3000 milliseconds for it to finish. If it did finish within the timeout, it return true, else false so you can use that to decide what to do next.
You can use a CancellationToken to communicate to the other thread that it result is no longer needed so it can stop gracefully.
Regards Gert-Jan
Run this function in thread and kill it after 3 seconds or check elapsed time inside this function(I think it's loop there).
Use an OS callbacks with a hi performance counter, then kill your thread, if exists
It is possible to execute a function in a separate thread and limit its execution with Thread.Join(millisecondsTimeout):
using System.Threading;
Thread workThread = new Thread(DoFunc);
workThread.Start(param);
if (!workThread.Join(3000))
{
// DoFunc() took longer than 3 seconds. Thread was aborted
}
private void DoFunc(object param)
{
// do some long work
}
Since C# and .net framework are not real-time environments, you can't guarantee even the 3 seconds count. Even if you were to get close to that, you would still have to call the
if(timeSpan > TimeSpan.FromSeconds(3) then goto endindentifier; before every other call in the method.
All this is just wrong so no, there is just no reliable way to do it from what I know.
Although you can try this solution
https://web.archive.org/web/20140222210133/http://kossovsky.net/index.php/2009/07/csharp-how-to-limit-method-execution-time
but I just wouldn't do such things in .net application.

Categories

Resources