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
Related
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();
}
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.
I have two methods I want to call within a loop. Step1() has to complete before Step2() is called. But in a loop, Step1() can start while Step2() is asynchronously executing. Should I simply wait for the Step2 task, before allowing any other 'Step2' tasks from being executed, as I do in the code below?
public MainViewModel()
{
StartCommand = new RelayCommand(Start);
}
public ICommand StartCommand { get; set; }
private async void Start()
{
await Task.Factory.StartNew(() =>
{
Console.WriteLine($"{DateTime.Now:hh:mm:ss.fff} - Started processing.");
for (int i = 0; i < 10; i++)
{
_counter++;
string result = Step1(i);
_step2Task?.Wait(); //Is this OK to do???
Step2(result).ConfigureAwait(false);
}
_step2Task?.Wait();
Console.WriteLine($"{DateTime.Now:hh:mm:ss.fff} - Finished processing.");
});
}
private string Step1(int i)
{
Thread.Sleep(5000); //simulates time-consuming task
Console.WriteLine($"{DateTime.Now:hh:mm:ss.fff} - Step 1 completed - Iteration {i}.");
return $"Step1Result{i}";
}
private async Task Step2(string result)
{
_step2Task = Task.Run(() =>
{
Thread.Sleep(4000); //simulates time-consuming task
Console.WriteLine($"{DateTime.Now:hh:mm:ss.fff} - Step 2 completed. - {result}");
});
await _step2Task;
}
Don't do any of this stuff; you will risk getting deadlocks all over the place. Also, don't move stuff onto threads unless it is CPU bound.
Start over:
Find every long-running synchronous method that is CPU intensive and write an async wrapper around it. The async wrapper should grab a worker thread, execute the CPU intensive task, and complete when the execution is done. Now you consistently have an abstraction in terms of tasks, not threads.
Move all of your control flow logic onto the UI thread.
Put an await everywhere that you mean "the code that comes after this must not execute until the awaited task is complete".
If we do that, your code gets a lot simpler:
// Return Task, not void
// Name async methods accordingly
private async Task StartAsync()
{
Console.WriteLine($"{DateTime.Now:hh:mm:ss.fff} - Started processing.");
Task task2 = null;
for (int i = 0; i < 10; i++)
{
// We cannot do Step2Async until Step1Async's task
// completes, so await it.
string result = await Step1Async(i);
// We can't run a new Step2Async until the old one is done:
if (task2 != null) {
await task2;
task2 = null;
}
// Now run a new Step2Async:
task2 = Step2Async(result);
// But *do not await it*. We don't care if a new Step1Async
// starts up before Step2Async is done.
}
// Finally, don't complete StartAsync until any pending Step2 is done.
if (task2 != null) {
await task2;
task2 = null;
}
Console.WriteLine($"{DateTime.Now:hh:mm:ss.fff} - Finished processing.");
}
private string Step1(int i)
{
// TODO: CPU intensive work here
}
private async Task<string> Step1Async(int i) {
// TODO: Run CPU-intensive Step1(i) on a worker thread
// return a Task<string> representing that work, that is
// completed when the work is done.
}
private void Step2(string result)
{
// TODO: CPU-intensive work here
}
private async Task Step2Async(string result)
{
// TODO: Again, make a worker thread that runs Step2
// and signals the task when it is complete.
}
Remember, await is the sequencing operation on workflows. It means don't proceed with this workflow until this task is complete; go find some other workflow.
Exercise: How would you write the code to represent the workflow:
Step1 must complete before Step2
Any number of Step2 may be running at the same time
All the Step2 must complete before Start completes
?
I've read this: Is it ok to await the same task from multiple threads - is await thread safe? and I don't feel clear about the answer, so here's a specific use case.
I have a method that performs some async network I/O. Multiple threads can hit this method at once, and I dont wan't them all to invoke a network request, If a request is already in progress I want to block/await the 2nd+ threads, and have them all resume once the single IO operation has completed.
How should I write the following pseudcode?
I'm guessing each calling thread really needs to get its own Task, so each can get it's own continuation, so instead of returning currentTask I should return a new Task which is completed by the "inner" Task from DoAsyncNetworkIO.
Is there a clean way to do this, or do I have to hand roll it?
static object mutex = new object();
static Task currentTask;
async Task Fetch()
{
lock(mutex)
{
if(currentTask != null)
return currentTask;
}
currentTask = DoAsyncNetworkIO();
await currentTask;
lock(mutex)
{
var task = currentTask;
currentTask = null;
return task;
}
}
You could use a SemaphoreSlim to ensure that only one thread actually executes the background thread.
Assume your base task (the one actually doing the IO) is in a method called baseTask(), which I shall emulate like so:
static async Task baseTask()
{
Console.WriteLine("Starting long method.");
await Task.Delay(1000);
Console.WriteLine("Finished long method.");
}
Then you can initialise a SemaphoreSlim like so, to act a bit like an AutoResetEvent with initial state set to true:
static readonly SemaphoreSlim signal = new SemaphoreSlim(1, 1);
Then wrap the call to baseTask() in a method that checks signal to see if this is the first thread to try to run baseTask(), like so:
static async Task<bool> taskWrapper()
{
bool firstIn = await signal.WaitAsync(0);
if (firstIn)
{
await baseTask();
signal.Release();
}
else
{
await signal.WaitAsync();
signal.Release();
}
return firstIn;
}
Then your multiple threads would await taskWrapper() rather than awaiting baseTask() directly.
Putting that altogether in a compilable console application:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
static class Program
{
static void Main()
{
for (int it = 0; it < 10; ++it)
{
Console.WriteLine($"\nStarting iteration {it}");
Task[] tasks = new Task[5];
for (int i = 0; i < 5; ++i)
tasks[i] = Task.Run(demoTask);
Task.WaitAll(tasks);
}
Console.WriteLine("\nFinished");
Console.ReadLine();
}
static async Task demoTask()
{
int id = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"Thread {id} starting");
bool firstIn = await taskWrapper();
Console.WriteLine($"Task {id}: executed: {firstIn}");
}
static async Task<bool> taskWrapper()
{
bool firstIn = await signal.WaitAsync(0);
if (firstIn)
{
await baseTask();
signal.Release();
}
else
{
await signal.WaitAsync();
signal.Release();
}
return firstIn;
}
static async Task baseTask()
{
Console.WriteLine("Starting long method.");
await Task.Delay(1000);
Console.WriteLine("Finished long method.");
}
static readonly SemaphoreSlim signal = new SemaphoreSlim(1, 1);
}
}
(The methods are all static because they are in a console app; in real code they would be non-static methods.)
await doesn't necessarily use continuations (the Task.ContinueWith kind) at all. Even when it does, you can have multiple continuations on one Task - they just can't all run synchronously (and you might run into some issues if you have a synchronization context).
Do note that your pseudo-code isn't thread-safe, though - you can't just do currentTask = DoAsyncNetworkIO(); outside of a lock. Only the await itself is thread-safe, and even then, only because the Task class that you're awaiting implements the await contract in a thread-safe way. Anyone can write their own awaiter/awaitable, so make sure to pay attention :)
I have an async operation dependent on another server which takes a mostly random amount of time to complete. While the async operation is running there is also processing going on in the 'main thread' which also takes a random amount of time to complete.
The main thread starts the asynchronous task, executes it's primary task, and checks for the result of the asynchronous task at the end.
The async thread pulls data and computes fields which are not critical for the main thread to complete. However this data would be nice to have (and should be included) if the computation is able to complete without slowing down the main thread.
I'd like to setup the async task to run at minimum for 2 seconds, but
to take all the time available between start and end of the main task.
It's a 'lazy timeout' in that it only timeouts if exceeded the 2
second runtime and the result is actually being requested. (The async
task should take the greater of 2 seconds, or the total runtime of the
main task)
EDIT (trying to clarify the requirements): If the async task has had a chance to run for 2 seconds, it shouldn't block the main thread at all. The main thread must allow the async task at least 2 seconds to run. Furthermore, if the main thread takes more than 2 seconds to complete, the async task should be allowed to run as long as the main thread.
I've devised a wrapper that works, however i'd prefer a solution that is actually of type Task. See my wrapper solution below.
public class LazyTimeoutTaskWrapper<tResult>
{
private int _timeout;
private DateTime _startTime;
private Task<tResult> _task;
private IEnumerable<Action> _timeoutActions;
public LazyTimeoutTaskWrapper(Task<tResult> theTask, int timeoutInMillis, System.DateTime whenStarted, IEnumerable<Action> onTimeouts)
{
this._task = theTask;
this._timeout = timeoutInMillis;
this._startTime = whenStarted;
this._timeoutActions = onTimeouts;
}
private void onTimeout()
{
foreach (var timeoutAction in _timeoutActions)
{
timeoutAction();
}
}
public tResult Result
{
get
{
var dif = this._timeout - (int)System.DateTime.Now.Subtract(this._startTime).TotalMilliseconds;
if (_task.IsCompleted ||
(dif > 0 && _task.Wait(dif)))
{
return _task.Result;
}
else
{
onTimeout();
throw new TimeoutException("Timeout Waiting For Task To Complete");
}
}
}
public LazyTimeoutTaskWrapper<tNewResult> ContinueWith<tNewResult>(Func<Task<tResult>, tNewResult> continuation, params Action[] onTimeouts)
{
var result = new LazyTimeoutTaskWrapper<tNewResult>(this._task.ContinueWith(continuation), this._timeout, this._startTime, this._timeoutActions.Concat(onTimeouts));
result._startTime = this._startTime;
return result;
}
}
Does anyone have a better solution than this wrapper?
I'd always start a 2 second task that, when it completes, marks your computation as cancelled . This saves you the strange "diff" time calculation. Here is some code:
Task mainTask = ...; //represents your main "thread"
Task computation = ...; //your main task
Task timeout = TaskEx.Delay(2000);
TaskCompletionSource tcs = new TCS();
TaskEx.WhenAll(timeout, mainTask).ContinueWith(() => tcs.TrySetCancelled());
computation.ContinueWith(() => tcs.TryCopyResultFrom(computation));
Task taskToWaitOn = tcs.Task;
This is pseudo-code. I only wanted to show the technique.
TryCopyResultFrom is meant to copy the computation.Result to the TaskCompletionSource tcs by calling TrySetResult().
Your app just uses taskToWaitOn. It will transition to cancelled after 2s. If the computation completes earlier, it will receive the result of that.
I don't think you can make Task<T> behave this way, because Result is not virtual and there also isn't any other way to change its behavior.
I also think you shouldn't even try to do this. The contract of the Result property is to wait for the result (if it's not available yet) and return it. It's not to cancel the task. Doing that would be very confusing. If you're cancelling the task, I think it should be obvious from the code that you're doing it.
If I were to do this, I would create a wrapper for the Task<T>, but it would look like this:
class CancellableTask<T>
{
private readonly Func<CancellationToken, T> m_computation;
private readonly TimeSpan m_minumumRunningTime;
private CancellationTokenSource m_cts;
private Task<T> m_task;
private DateTime m_startTime;
public CancellableTask(Func<CancellationToken, T> computation, TimeSpan minumumRunningTime)
{
m_computation = computation;
m_minumumRunningTime = minumumRunningTime;
}
public void Start()
{
m_cts = new CancellationTokenSource();
m_task = Task.Factory.StartNew(() => m_computation(m_cts.Token), m_cts.Token);
m_startTime = DateTime.UtcNow;
}
public T Result
{
get { return m_task.Result; }
}
public void CancelOrWait()
{
if (m_task.IsCompleted)
return;
TimeSpan remainingTime = m_minumumRunningTime - (DateTime.UtcNow - m_startTime);
if (remainingTime <= TimeSpan.Zero)
m_cts.Cancel();
else
{
Console.WriteLine("Waiting for {0} ms.", remainingTime.TotalMilliseconds);
bool finished = m_task.Wait(remainingTime);
if (!finished)
m_cts.Cancel();
}
}
}
Note that the computation has a CancellationToken parameter. That's because you can't force cancellation (without dirty tricks like Thread.Abort()) and the computation has to explicitly support it, ideally by executing cancellationToken.ThrowIfCancellationRequested() at appropriate times.