How can I wait for the task to start. The following code fails:
var asyncmethod = ...a Task<TReturn>, with .Start() called on it...;
int waitcounter = 0;
while (!asyncmethod.Wait(1000))
{
waitcounter++;
Log("waiting very long...");
}
ret = asyncmethod.Result;
The asyncmethod.Wait(1000) waits 1 seconds as expected, but the Task is in the state WaitingToRun and will never start running when Wait()ing. On the other hand, when .Result is called, it will start running. How to get it to run without calling .Result?
the Task is in the state WaitingToRun and will never start running when Wait()ing
When a task is in the WaitingToRun state, that means it is ready to start running and is just waiting for its scheduling context to be available, so it can be scheduled and run (as I describe on my blog).
Since the task is still in this state after Wait(1000) finishes, then presumably the task is waiting for the scheduling context that is used by the calling thread, and thus cannot be scheduled until that thread is free.
Task.Result can trigger task inlining and execute task, but apparently Wait() cannot.
Both .Result and .Wait() will permit the task to be inlined, but of course .Wait(x) cannot because it has to honor the timeout.
However, neither .Result nor .Wait() will guarantee inlining - and it's important to keep that in mind when writing reliable code.
the code shouldn't break, regardless of if the task is scheduled on the "current" or a separate thread.
That's an extremely difficult requirement to satisfy. Are you sure you need that?
The easiest solution would be to wait asynchronously:
Task<T> asyncmethod = ...;
int waitcounter = 0;
while (await Task.WhenAny(Task.Delay(1000), asyncmethod) != asyncmethod)
{
waitcounter++;
Log("waiting very long...");
}
ret = await asyncmethod;
Just wait for the task to be completed using:
asyncmethod.Start();
asyncmethod.Wait(); // not needed in most cases
// but if used, the task is completed at this point.
var ret = asyncmethod.Result; // automatically waits for the task to be completed
but basically, the waiting is not neccesary, unless you have a reason for this. From the Task<TResult>.Result-docs:
The get accessor for this property ensures that the asynchronous
operation is complete before returning. Once the result of the
computation is available, it is stored and will be returned
immediately on later calls to Result. (from msdn)
Not really sure why you're doing this, but this can be achieved without blocking the calling thread using Task.IsCompleted and Task.Delay:
public async Task FooAsync()
{
var waitCounter = -1;
var task = Task.Run(() => { });
do
{
waitCounter++;
await Task.Delay(1000);
}
while (!task.IsCompleted)
}
This snippet will call Log a single time if the Task takes more than 1000ms to complete.
private async static void StartTask()
{
Task<object> asyncmethod = ... ;
LogDurationTooLong(asyncmethod, 1000);
var result = await asyncmethod;
}
/// <summary>
/// Logs if a task takes too long to complete.
/// </summary>
/// <param name="asyncmethod">The task to reference.</param>
/// <param name="duration">The duration after which a log entry is made.</param>
private async static void LogDurationTooLong(Task asyncmethod, int duration)
{
Task completedTask = await Task.WhenAny(Task.Delay(duration), asyncmethod);
if (completedTask != asyncmethod)
{
Log("waiting very long...");
}
}
Related
In the following article, Stephen Toub describes how to build a ManualResetEvent using the TPL. In particular, he states that in the following method:
public void Set()
{
var tcs = m_tcs;
Task.Factory.StartNew(
s => ((TaskCompletionSource<bool>)s).TrySetResult(true),
tcs,
CancellationToken.None,
TaskCreationOptions.PreferFairness,
TaskScheduler.Default);
tcs.Task.Wait();
}
the tcs.Task.Wait() will "block until the task being completed is actually finished (not including the task’s synchronous continuations, just the task itself)". Why won't we block on any synchronous continuations? That is, what will prevent any synchronous continuations on any Tasks awaiting tcs.Task's completion from executing synchronously?
He means that if you do is this way:
public void Set()
{
m_tsc.TrySetResult(true);
}
Then all synchronous continuations of TaskCompletionSource Task will run synchronously on this same thread, blocking Set method for the duration.
However if you do it the way described in your question, then all those continuations will still run, but on thread pool thread, because that's where you execute TrySetResult. As soon as TaskCompletionSource task completes - your tcs.Task.Wait() will return, before synchronous continuations will run. So in effect, Set method will not block waiting for them to complete.
This is because the work in ContinueWith is a different task. All ContinueWith variants say:
Returns
A new continuation Task.
and in the Remarks we can read:
Remarks
The returned Task will not be scheduled for execution until the current task has completed.
BTW. These days ContinueWith is discouraged and await is preferred in almost all cases.
the tcs.Task.Wait() will "block until the task being completed is actually finished (not including the task’s synchronous continuations, just the task itself)". Why won't we block on any synchronous continuations? That is, what will prevent any synchronous continuations on any Tasks awaiting tcs.Task's completion from executing synchronously?
Your question is about Tasks in general, not about the TaskCompletionSource.Task in particular. The answer is that when an incomplete Task is waited, the Wait is performed by a ManualResetEventSlim, which is Set by a task continuation, which is prioritized in front of all other continuations that might be attached previously. Here is a part of the private SpinThenBlockingWait method, from the Task.cs source code:
private bool SpinThenBlockingWait(int millisecondsTimeout,
CancellationToken cancellationToken)
{
bool infiniteWait = millisecondsTimeout == Timeout.Infinite;
uint startTimeTicks = infiniteWait ? 0 : (uint)Environment.TickCount;
bool returnValue = SpinWait(millisecondsTimeout);
if (!returnValue)
{
var mres = new SetOnInvokeMres();
try
{
AddCompletionAction(mres, addBeforeOthers: true);
if (infiniteWait)
{
bool notifyWhenUnblocked = ThreadPool.NotifyThreadBlocked();
try
{
returnValue = mres.Wait(Timeout.Infinite, cancellationToken);
//...
This method is invoked internally by the Wait, when the task is not complete at the moment, and the current thread must be blocked. The SetOnInvokeMres is a small class that inherits from the ManualResetEventSlim:
private sealed class SetOnInvokeMres : ManualResetEventSlim, ITaskCompletionAction
{
internal SetOnInvokeMres() : base(false, 0) { }
public void Invoke(Task completingTask) { Set(); }
public bool InvokeMayRunArbitraryCode => false;
}
The interesting point is the addBeforeOthers: true argument. This ensures that the ManualResetEventSlim will be signaled before invoking any continuation that is associated with user-supplied code. The Task Parallel Library exposes no public API that allows to attach a continuation with addBeforeOthers: true. Actually this parameter seems to exist exclusively for supporting the signaling of ManualResetEventSlims with priority.
I want to create a Task, which may run for many minutes, collecting data via an API call to another system. At some point in the future I need to stop the task and return the collected data. This future point is unknown at the time of starting the task.
I have read many question about returning data from tasks, but I can't find any that answer this scenario. I may be missing a trick, but all of the examples actually seem to wait in the man thread for the task to finish before continuing. This seems counter-intuitive, surely the purpose of a task is to hand off an activity whilst continuing with other activities in your main thread?
Here is one of those many examples, taken from DotNetPearls..
namespace TaskBasedAsynchronousProgramming
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"Main Thread Started");
Task<double> task1 = Task.Run(() =>
{
return CalculateSum(10);
});
Console.WriteLine($"Sum is: {task1.Result}");
Console.WriteLine($"Main Thread Completed");
Console.ReadKey();
}
static double CalculateSum(int num)
{
double sum = 0;
for (int count = 1; count <= num; count++)
{
sum += count;
}
return sum;
}
}
}
Is it possible to do what I need, and have a long-running task running in parallel, stop it and return the data at an arbitrary future point?
Here is a sample application how you can do that:
static double partialResult = -1;
static void Main()
{
CancellationTokenSource calculationEndSignal = new(TimeSpan.FromSeconds(3));
Task meaningOfLife = Task.Run(() =>
GetTheMeaningOfLife(calculationEndSignal.Token),
calculationEndSignal.Token);
calculationEndSignal.Token.Register(() => Console.WriteLine(partialResult));
Console.ReadLine();
}
static async Task GetTheMeaningOfLife(CancellationToken cancellationToken)
{
foreach (var semiResult in Enumerable.Range(1, 42))
{
partialResult = semiResult;
cancellationToken.ThrowIfCancellationRequested();
await Task.Delay(1000);
}
}
partialResult is a shared variable between the two threads
The worker thread (GetTheMeaningOfLife) only writes it
The main thread (Main) only reads it
The read operation is performed only after the Task has been cancelled
calculationEndSignal is used to cancel the long-running operation
I've have specified a timeout, but you can call the Cancel method if you want
meaningOfLife is the Task which represents the long-running operation call
I have passed the CancellationToken to the GetTheMeaningOfLife and to the Task.Run as well
For this very simple example the Task.Run should not need to receive the token but it is generally a good practice to pass there as well
Register is receiving a callback which should be called after the token is cancelled
ReadLine can be any other computation
I've used ReadLine to keep the application running
GetTheMeaningOfLife simply increments the partialResult shared variable
either until it reaches the meaning of life
or until it is cancelled
Here is one approach. It features a CancellationTokenSource that is used as a stopping mechanism, instead of its normal usage as a cancellation mechanism. That's because you want to get the partial results, and a canceled Task does not propagate results:
CancellationTokenSource stoppingTokenSource = new();
Task<List<int>> longRunningTask = Task.Run(() =>
{
List<int> list = new();
for (int i = 1; i <= 60; i++)
{
if (stoppingTokenSource.IsCancellationRequested) break;
// Simulate a synchronous operation that has 1 second duration.
Thread.Sleep(1000);
list.Add(i);
}
return list;
});
Then, somewhere else in your program, you can send a stopping signal to the task, and then await asynchronously until the task acknowledges the signal and completes successfully. The await will also propagate the partial results:
stoppingTokenSource.Cancel();
List<int> partialResults = await longRunningTask;
Or, if you are not in an asynchronous workflow, you can wait synchronously until the partial results are available:
stoppingTokenSource.Cancel();
List<int> partialResults = longRunningTask.Result;
Suppose I have some async task that can sometimes run fast and sometimes slow,
public Random seed = new Random();
private async Task<string> _Work()
{
int time = seed.Next(0, 5000);
string result = string.Format("Worked for {0} milliseconds", time);
await Task.Delay(time);
return result;
}
public void SomeMethod()
{
_Work(); // starts immediately? Am I right?
// since _Work() will be executed immediately before ContinueWith() is executed,
// will there be a chance that callback will not be called if _Work completes very quickly,
// like before ContinueWith() can be scheduled?
_Work().ContinueWith(callback)
}
Is the callback in Task.ContinueWith() guaranteed to run in the above scenario?
will there be a chance that callback will not be called if _Work completes very quickly?
No. Continuations passed to ContinueWith will always be scheduled. If the task is already complete, they will be scheduled immediately. The task uses a thread-safe kind of "gate" to ensure that a continuation passed to ContinueWith will always be scheduled; there is a race condition (of course) but it's properly handled so that the continuation is always scheduled regardless of the results of the race.
In my current project, I have a piece of code that, after simplifying it down to where I'm having issues, looks something like this:
private async Task RunAsync(CancellationToken cancel)
{
bool finished = false;
while (!cancel.IsCancellationRequested && !finished)
finished = await FakeTask();
}
private Task<bool> FakeTask()
{
return Task.FromResult(false);
}
If I use this code without awaiting, I end up blocking anyway:
// example 1
var task = RunAsync(cancel); // Code blocks here...
... // Other code that could run while RunAsync is doing its thing, but is forced to wait
await task;
// example 2
var task = RunAsync(cancelSource.Token); // Code blocks here...
cancelSource.Cancel(); // Never called
In the actual project, I'm not actually using FakeTask, and there usually will be some Task.Delay I'm awaiting in there, so the code most of the time doesn't actually block, or only for a limited amount of iterations.
In unit testing, however, I'm using a mock object that does pretty much do what FakeTask does, so when I want to see if RunAsync responds to its CancellationToken getting cancelled the way I expect it to, I'm stuck.
I have found I can fix this issue by adding for example await Task.Delay(1) at the top of RunAsync, to force it to truly run asynchronous, but this feels a bit hacky. Are there better alternatives?
You have an incorrect mental picture of what await does. The meaning of await is:
Check to see if the awaitable object is complete. If it is, fetch its result and continue executing the coroutine.
If it is not complete, sign up the remainder of the current method as the continuation of the awaitable and suspend the coroutine by returning control to the caller. (Note that this makes it a semicoroutine.)
In your program, the "fake" awaitable is always complete, so there is never a suspension of the coroutine.
Are there better alternatives?
If your control flow logic requires you to suspend the coroutine then use Task.Yield.
Task.FromResult actually runs synchronously, as would await Task.Delay(0). If you want to actually simulate asynchronous code, call Task.Yield(). That creates an awaitable task that asynchronously yields back to the current context when awaited.
As #SLaks said, your code will run synchronously. One thing is running async code, and another thing is running parallel code.
If you need to run your code in parallel you can use Task.Run.
class Program
{
static async Task Main(string[] args)
{
var tcs = new CancellationTokenSource();
var task = Task.Run(() => RunAsync("1", tcs.Token));
var task2 = Task.Run(() => RunAsync("2", tcs.Token));
await Task.Delay(1000);
tcs.Cancel();
Console.ReadLine();
}
private static async Task RunAsync(string source, CancellationToken cancel)
{
bool finished = false;
while (!cancel.IsCancellationRequested && !finished)
finished = await FakeTask(source);
}
private static Task<bool> FakeTask(string source)
{
Console.WriteLine(source);
return Task.FromResult(false);
}
}
C#'s async methods execute synchronously up to the point where they have to wait for a result.
In your example there is no such point where the method has to wait for a result, so the loop keeps running forever and thereby blocking the caller.
Inserting an await Task.Yield() to simulate some real async work should help.
I am working in Xamarin where I have a Task that I start at the first menupage, go through several other menupages, and then want to wait for it's completion when opening an endpage. To do this I save the task in a static field when starting it:
private static Task myTask;
public static void sync(User user)
{
if (myTask== null || myTask.IsCompleted) {
myTaskStarted = true;
//Note: do not trust on the variable being filled in immediately after the start of the task. It takes a minute. Use the flag
myTask= AsyncMyTask(user);
}
}
And then later I call a method from another page that is simply supposed to wait for myTask to finnish by calling myTask.Wait() after doing some checks on myTask having been started and not being null. But I see that once I call myTask.Wait() myTask is stuck and no longer progresses in the debugger. It's stuck. If I replace myTask.Wait() by myTask.Wait(1000) myTask is frozen for the duration of the timeout. After the timeout it continues. This is not the behaviour that is described in the documentation. Can anyone explain why the AsyncMyTask method is blocked when you call myTask.Wait() from the UI thread?
As requested: the AwaitMyTask method:
public async static Task<Boolean> AwaitMyTask()
{
if(!myTaskStarted && myTask== null)
{
return false;
} else
{
while (myTask== null)
{
Task.Delay(10);
}
}
//Stuck on the line below
myTask.Wait();
myTaskStarted = false;
return myTask.IsCompleted;
}
Task.Wait is a synchronously awaiting the task which blocks the thread. Unless you can point to a documentation stating something else, I'd say that it's expected behavior as described in https://msdn.microsoft.com/en-us/library/dd235635(v=vs.110).aspx
Wait is a synchronization method that causes the calling thread to wait until the current task has completed. ...