how to cancel a function after a while? - c#

I want to know how can I cancel a function after a certain time!
for example, how can I cancel this function?
private async Task function()
{
try
{
while (true)
{
//mycode
}
}
catch{ }
}

how can I cancel this function?
Normally, awaitable methods will take a CancellationToken, so you'd just pass it on through:
private async Task functionAsync(CancellationToken cancellationToken)
{
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); //mycode
}
}

Some time ago i faced the same issue and found a pretty good solution working for me. I am separating async calls to another service via wcf this way (see my code below) by doing two things to cancel after a maximum time:
You can use CancellationToken in combination with a second Task to run parallel to your running task and cancel it if necessary:
private const int TimeOut = 50000;
public static async Task<T> HandleServiceCall<T>(Func<Task<T>> doServiceCall, CancellationTokenSource source) where T : class
{
var delaySource = new CancellationTokenSource(TimeSpan.FromSeconds(50));
source.Token.ThrowIfCancellationRequested();
var res = doServiceCall();
if (await Task.WhenAny(res, Task.Delay(TimeSpan.FromMilliseconds(TimeOut), delaySource.Token)) == res)
{
delaySource.Cancel();
await res;
}
else
{
source.Cancel();
throw new Exception("Your Text");
}
return await res;
}
You can call this Method for example this way:
var source = new CancellationTokenSource(TimeSpan.FromSeconds(50));
source.Token.ThrowIfCancellationRequested();
MyWrapperClass.HandleServiceCall(async () => await MyAsyncMethod(source.Token), source).Result
To clarify what is done here:
I am creating a cancellation Token for my Task with a given max TimeSpan and then give this Token to the async Method which should be called.
This call is given as a func into my HandleServiceCall Method.
This Method will create another CancellationToken with a given greater TimeSpan, which will Run as a delayed Task (task.Delay will just wait until the Token is triggered).
Task.WhenAny will look if the normal async task or the delayed task is finishing first. If it is the delayed one, your maximum time has expired and an exception is thrown.
Greetings
Konstantin

You could use the Timer class, start it when you want it to (beginning of the program presumably), and use some like a simple if statement to stop it, such as *if timer is greater than set time, end program. *

I add small example
static CancellationTokenSource cts;
static void Main(string[] args)
{
cts = new CancellationTokenSource();
Task.Factory.StartNew(test);
cts.Cancel();
}
private async static void test()
{
await function(cts.Token);
}
static async Task function(CancellationToken ct)
{
try
{
while (!ct.IsCancellationRequested)
{
Thread.Sleep(1000);
//mycode
}
}
catch { }
}

Related

C# - Wait for Task with return value

I want to have a code block, which should be executed with a maximum time limit. If the functions hangs, it should be aborted.
From this question I adapted the following solution:
public static void ExecuteWithTimeLimit(int timeLimit_milliseconds, Func<bool> codeBlock)
{
Task task = Task.Factory.StartNew(() =>
{
codeBlock();
});
task.Wait(timeLimit_milliseconds);
}
This works as I want it to behave: If the code codeBlock hangs and takes to long, the task is aborted.
However, I want the Task to have a return value so I can use task.Result. If I implement this into the code, it doesn't work any more.
In fact, the task is not cancled and the GUI freezes completly.
public static void ExecuteWithTimeLimit(int timeLimit_milliseconds, Func<bool> codeBlock)
{
Task<bool> task = Task<bool>.Factory.StartNew(() =>
{
return codeBlock();
});
task.Wait(timeLimit_milliseconds);
}
What is the correct way to execute Methods with a return value with a maximum time limit?
I would recommend creating a task method and using await. This will release the thread so application doesn't lock up, and once result is available it will jump back into that thread Here is an example:
public async Task MyMethodAsync()
{
Task<string> longRunningTask = LongRunningOperationAsync();
// independent work which doesn't need the result of LongRunningOperationAsync can be done here
//and now we call await on the task
string result = await longRunningTask;
//use the result
Console.WriteLine(result);
}
public async Task<string> LongRunningOperationAsync() // assume we return an int from this long running operation
{
//Perform your task in here
await Task.Delay(5000); // 5 second delay to show how it releases thread
return "Task Complete";
}
There's a lot of mucking around with cancellation tokens with tasks. I'd suggest making your life easier and use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive and add using System.Reactive.Linq; - then you can do this:
public static async Task<bool> ExecuteWithTimeLimit(TimeSpan timeLimit, Func<bool> codeBlock)
=> await Observable.Amb(
Observable.Timer(timeLimit).Select(_ => false),
Observable.Start(() => codeBlock()));
Observable.Amb takes 2 or more observables and only returns values from whichever observable fires first. Observable.Timer fires a single value after the TimeSpan provided. Observable.Start executes what ever code and returns a single value that is the result of that code.
Effectively Amb is a race between the timer and the code.
Now I can run it like this:
Task<bool> task =
ExecuteWithTimeLimit(TimeSpan.FromSeconds(1.0), () =>
{
Console.WriteLine("!");
Thread.Sleep(TimeSpan.FromSeconds(2.0));
Console.WriteLine("!!");
return true;
});
task.Wait();
Console.WriteLine(task.Result);
When I run that I get this on the console:
!
False
!!
If I change the timeLimit to TimeSpan.FromSeconds(3.0) then I get this:
!
!!
True
Actually I found a solution by canceling the task after the time limit:
public static void ExecuteWithTimeLimit(int timeLimit_milliseconds, Func<bool> codeBlock)
{
var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
Task<bool> task = Task<bool>.Factory.StartNew(() =>
{
try
{
return codeBlock();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Exeption", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
}, cancellationToken);
task.Wait(timeLimit_milliseconds);
cancellationTokenSource.Cancel();
}

How to determine CancellationTokenSource scope?

Instead of using conventional threading, I am using async/await to implement a long-running job that will be called from various scenarios such as Desktop/Web/Mobile.
This question is about design considerations when using CancellationTokenSource/CancellationToken objects. Consider the following code written in .NET Core 5:
System
System.Collections.Generic
System.Diagnostics
System.IO
System.Threading
System.Threading.Tasks
[STAThread]
private static async Task Main ()
{
using (var job = new Job())
//using (var source = new CancellationTokenSource())
{
var watch = Stopwatch.StartNew();
job.OnJobProgress += (sender, e) => { Console.WriteLine (watch.Elapsed); };
Task.Run (async () => await job.StartAsync());
//Task.Run (async () => await job.StartAsync (source.Token));
do
{
await Task.Delay (100);
if ((Console.KeyAvailable) && (Console.ReadKey ().Key == ConsoleKey.Escape))
{
//source.Cancel();
await job.CancelAsync();
break;
}
}
while (job.Running);
}
}
public class Job : IDisposable
{
public EventHandler OnJobProgress;
private bool _Running = false;
private readonly object SyncRoot = new object();
private CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
public bool Running => this._Running;
public async Task StartAsync () => await this.StartAsync(CancellationToken.None);
public async Task StartAsync (CancellationToken cancellationToken) => await this.ProcessAsync(cancellationToken);
public void Cancel ()
{
this.CancellationTokenSource?.Cancel();
do { Thread.Sleep (10); } while (this._Running);
}
public async Task CancelAsync ()
{
this.CancellationTokenSource?.Cancel();
do { await Task.Delay (10); } while (this._Running);
}
private async Task ProcessAsync (CancellationToken cancellationToken)
{
lock (this.SyncRoot)
{
if (this._Running) { return; }
else { this._Running = true; }
}
do
{
await Task.Delay (100);
this.OnJobProgress?.Invoke (this, new EventArgs());
}
while (!cancellationToken.IsCancellationRequested);
lock (this.SyncRoot)
{
this._Running = false;
this.CancellationTokenSource?.Dispose();
this.CancellationTokenSource = new CancellationTokenSource();
}
}
public void Dispose () => this.Cancel();
}
Notice the three commented lines in the Main method as well as the Cancel and CancelAsync methods. My gut says that there should be a locking mechanism in place in the Cancel methods instead of the Process method. Depending on where the CancellationToken comes from, are there any potential deadlocks in this implementation? Somehow, I am not comfortable with the do/while blocking mechanism.
Any thoughts would be appreciated.
AUXILIARY QUESTION: Since CancellationToken is a readonly struct and being passed around by value, how is it that calling Cancel on the CancellationTokenSource modifies the CancellationToken.IsCancellationRequested property? Perhaps that was the source of confusion all along.
This is a job for Task.WhenAny. Await the first job to complete from two: either the one you want to really want to complete or the one representing user's impatience by hitting the ESC key or appropriate mobile touch.
Pseudocode:
mainTask = Setup main task, take the token as input. That's it.
userInterruptTask = Setup user action monitoring task, and in it's continuation or as part of its natural loop's time to end (the ESC key), call Cancel. Note, in this loop, there is NO check against a boolean value; it just goes until it must cancel, and then is done via break/return; the other task goes to done if it is properly listening for cancellation.
So, when either task completes, you're done.
var ret = await Task.WhenAny(mainTask, userInterruptTask);
If it matters at this point, get the value of ret and act accordingly. Task.WhenAny returns
A task that represents the completion of one of the supplied tasks. The return task's Result is the task that completed.
For a specific answer to "what is the scope" of the token... its scope is everything that may act on it. Cancellation in TPL is 100% cooperative, so all tasks that care to set cancellation or look for cancellation are in play.
For your auxiliary question, I can understand your confusion. I hadn't thought of it before, myself, but the answer turns out to be simple. The implementation of that property delegates to the token source:
public bool IsCancellationRequested
=> _source != null && _source.IsCancellationRequested;
where the CancellationTokenSource is a stateful class.

Switch new Task(()=>{ }) for Func<Task>

In an answer to one of my other questions, I was told that use of new Task(() => { }) is not something that is a normal use case. I was advised to use Func<Task> instead. I have tried to make that work, but I can't seem to figure it out. (Rather than drag it out in the comments, I am asking a separate question here.)
My specific scenario is that I need the Task to not start right when it is declared and to be able to wait for it later.
Here is a LinqPad example using new Task(() => { }). NOTE: This works perfectly! (Except that it uses new Task.)
static async void Main(string[] args)
{
// Line that I need to swap to a Func<Task> somehow.
// note that this is "cold" not started task
Task startupDone = new Task(() => { });
var runTask = DoStuff(() =>
{
//+++ This is where we want to task to "start"
startupDone.Start();
});
//+++ Here we wait for the task to possibly start and finish. Or timeout.
// Note that this times out at 1000ms even if "blocking = 10000" below.
var didStartup = startupDone.Wait(1000);
Console.WriteLine(!didStartup ? "Startup Timed Out" : "Startup Finished");
await runTask;
Console.Read();
}
public static async Task DoStuff(Action action)
{
// Swap to 1000 to simulate starting up blocking
var blocking = 1; //1000;
await Task.Delay(500 + blocking);
action();
// Do the rest of the stuff...
await Task.Delay(1000);
}
I tried swapping the second line with:
Func<Task> startupDone = new Func<Task>(async () => { });
But then the lines below the comments with +++ in them don't work right.
I swapped the startupDone.Start() with startupDone.Invoke().
But startupDone.Wait needs the task. Which is only returned in the lambda. I am not sure how to get access to the task outside the lambda so I can Wait for it.
How can use a Func<Task> and start it in one part of my code and do a Wait for it in another part of my code? (Like I can with new Task(() => { })).
The code you posted cannot be refactored to make use of a Func<Task> instead of a cold task, because the method that needs to await the task (the Main method) is not the same method that controls the creation/starting of the task (the lambda parameter of the DoStuff method). This could make the use of the Task constructor legitimate in this case, depending on whether the design decision to delegate the starting of the task to a lambda is justified. In this particular example the startupDone is used as a synchronization primitive, to signal that a condition has been met and the program can continue. This could be achieved equally well by using a specialized synchronization primitive, like for example a SemaphoreSlim:
static async Task Main(string[] args)
{
var startupSemaphore = new SemaphoreSlim(0);
Task runTask = RunAsync(startupSemaphore);
bool startupFinished = await startupSemaphore.WaitAsync(1000);
Console.WriteLine(startupFinished ? "Startup Finished" : "Startup Timed Out");
await runTask;
}
public static async Task RunAsync(SemaphoreSlim startupSemaphore)
{
await Task.Delay(500);
startupSemaphore.Release(); // Signal that the startup is done
await Task.Delay(1000);
}
In my opinion using a SemaphoreSlim is more meaningful in this case, and makes the intent of the code clearer. It also allows to await asynchronously the signal with a timeout WaitAsync(Int32), which is not something that you get from a Task out of the box (it is doable though).
Using cold tasks may be tempting in some cases, but when you revisit your code after a month or two you'll find yourself confused, because of how rare and unexpected is to have to deal with tasks that may or may have not been started yet.
I always try my hardest to never have blocking behavior when dealing with anything async or any type that represents potential async behavior such as Task. You can slightly modify your DoStuff to facilitate waiting on your Action.
static async void Main(string[] args)
{
Func<CancellationToken,Task> startupTask = async(token)=>
{
Console.WriteLine("Waiting");
await Task.Delay(3000, token);
Console.WriteLine("Completed");
};
using var source = new CancellationTokenSource(2000);
var runTask = DoStuff(() => startupTask(source.Token), source.Token);
var didStartup = await runTask;
Console.WriteLine(!didStartup ? "Startup Timed Out" : "Startup Finished");
Console.Read();
}
public static async Task<bool> DoStuff(Func<Task> action, CancellationToken token)
{
var blocking = 10000;
try
{
await Task.Delay(500 + blocking, token);
await action();
}
catch(TaskCanceledException ex)
{
return false;
}
await Task.Delay(1000);
return true;
}
First, the type of your "do this later" object is going to become Func<Task>. Then, when the task is started (by invoking the function), you get back a Task that represents the operation:
static async void Main(string[] args)
{
Func<Task> startupDoneDelegate = async () => { };
Task startupDoneTask = null;
var runTask = await DoStuff(() =>
{
startupDoneTask = startupDoneDelegate();
});
var didStartup = startupDoneTask.Wait(1000);
Console.WriteLine(!didStartup ? "Startup Timed Out" : "Startup Finished");
}

Take the Last Requested Async Result and Cancelling Previous Unfinished Tasks

I have multiple heavy job calculation requests. The job may take different time. By using async and await I want to take the last requested result with canceling eventually unfinished previous tasks.
Currently I'm using BackGroundWorker with setting a job ID. I used only the the result with the last requested ID.
Can I rewrite the code with using async await?
private int backtestId;
private void PrepareStrategyCalculation()
{
backtestId = backtestManager.GetNextBacktestId();
strategy.BacktestId = backtestId;
backtestManager.StartBacktestWorker(strategy.Clone());
}
private void BacktestManager_StrategyBacktested(object sender, StrategyBacktestEventArgs e)
{
if (e.BacktestObject.Strategy.BacktestId != backtestId) return;
var calculatedStrategy = e.BacktestObject.Strategy;
...
}
EDIT:
Is this a solution?
private int backtestId;
private async void PrepareStrategyCalculation()
{
backtestId = backtestManager.GetNextBacktestId();
strategy.BacktestId = backtestId;
var calculatedStrategy = await backtestManager.StartBacktestAsync(strategy.Clone());
if (calculatedStrategy.BacktestId != backtestId) return;
...
}
Assuming your code is CPU-bound, then Task.Run is a suitable substitute for BackgroundWorker.
You can use CancellationTokenSource to cancel tasks. So, something like this would work, assuming that StartBacktestAsync is called from a single-threaded context such as a UI thread:
private CancellationTokenSource _cts;
async Task StartBacktestAsync()
{
if (_cts != null)
_cts.Cancel();
_cts = new CancellationTokenSource();
try
{
var token = _cts.Token;
await Task.Run(() => Backtest(token));
}
catch (OperationCanceledException)
{
// Any special logic for a canceled operation.
}
}
void Backtest(CancellationToken token)
{
... // periodically call token.ThrowIfCancellationRequested();
}

Pausing a task within Task.Factory.StartNew

In my Asp.Net MVC 5 project I have a ~3 minute task that I pass to Task.Factory.StartNew().
I would like to pause the task from within the task if there is a validation issue in one of the steps of my code running in the task. I don't want to delay it async because the rest of the task will continue to run, which can't happen.
Could I use thread.sleep() without any repercussions since I'm within a task? I read that I may have to use TaskScheduler.Default to have the Task.Factory create a new thread for each task.
I'm using a PauseToken similar to a CancellationToken so I'll be able to resume the task or cancel this task based on user input.
Multithreading really scares me, and I don't want to overlook something.
Here is an example of the Thread.Sleep implementation:
public void WaitIfPaused(PauseToken pauseToken, CancellationToken cancellationToken, IProgressBar progressBar)
{
//TODO: If paused for an hour notify user via noty and abort the task to keep it from completing by cancellation via cancellationToken.
//wait for 1 hour
for (int i = 0; i < 3600; i++)
{
ThrowExceptionIfCancelled(cancellationToken, progressBar);
if (pauseToken.IsPaused)
{
Thread.Sleep(1000);
}
else
{
break;
}
}
}
PauseToken: http://blogs.msdn.com/b/pfxteam/archive/2013/01/13/cooperatively-pausing-async-methods.aspx
Requested: Implementation of task structure in shared code library.
public void StartTask(params object[] data)
{
//throw an exception if no ITask was found
if (_taskToRun == null)
throw new Exception("Task cannot be null");
//set up task cancellation
CancellationTokenSource = new CancellationTokenSource();
var cancellationToken = CancellationTokenSource.Token;
//set up task pausing
PauseTokenSource = new PauseTokenSource();
var pauseToken = PauseTokenSource.Token;
//start a new task using the Task that was set
_task = Task.Factory.StartNew(() => _taskToRun.Execute(cancellationToken, pauseToken, data), cancellationToken);
}
My Execute method that is invoked by _taskToRun.Execute:
Public override void Execute(CancellationToken cancellationToken, PauseToken pauseToken, params object[] data)
{
var managerList = (List<IFileManager>) data[0];
var instr = (List<InstructionSet>) data[1];
ProcessInstructions(managerList, instr, cancellationToken, pauseToken);
}
Update due to comments:
Code example: 3 instructions
For(var instruction in instructions)
{
instruction.Execute();
}
In my execute method I run into a scenario for pause and call WaitWhilePausedAsync from within the execute. It will continue to execute the other two instructions, but pause the only the current instructions execute method.
Edit: By awaiting instruction.Execute() it will wait until instruction.Execute() completes or is unpaused.
Final Edit:
I was able to resolve the issue by awaiting the Execute method and making it async like Servy and I3arnon suggested.
Final Code Sample:
foreach(var instruction in instructions)
{
try
{
await instruction.Execute(pauseToken);
}
catch(InvalidOperationException)
{
pauseTokenSource.IsPaused = true;
//ask if user wants to cancel or resume.
}
}
//Simplified
public async Task<bool> Execute(PauseToken pauseToken)
{
await pauseToken.WaitWhilePausedAsync();
//do work
}
You can safely use Thread.Sleep. The only drawback is that the thread would be wasted blocking synchronously.
You should be using await Task.Delay(1000) instead. The code after that line would not execute until the wait is complete, but you won't be wasting a thread in the meantime:
public async Task WaitIfPausedAsync(PauseToken pauseToken, CancellationToken cancellationToken, IProgressBar progressBar)
{
for (int i = 0; i < 3600; i++)
{
ThrowExceptionIfCancelled(cancellationToken, progressBar);
if (pauseToken.IsPaused)
{
await Task.Delay(1000)
}
else
{
break;
}
}
}
Edit: I was unaware of PauseToken.WaitWhilePausedAsync. You should definitly use that instead of replicating that yourself with polling over PauseToken.IsPaused

Categories

Resources