I have an async method after the completion of which I wish to run another method. This works fine if I simply call the method and add .ContinueWith()
However, I have a new requirement which is to only start the task if I am able to add it to a concurrent dictionary.
I wish to construct the task, attempt to add it and then start the task
However, it seems that Task.Start() immediately completes the task causing the continue action to run and any waits to.. not wait.
can anyone explain why this happens and the correct way to achieve my goal?
namespace UnitTestProject2
{
[TestClass]
public class taskProblem
{
[TestMethod]
public void Test()
{
CancellationTokenSource cancel = new CancellationTokenSource();
ConcurrentDictionary<Guid, Task> tasks = new ConcurrentDictionary<Guid,Task>();
Guid id = Guid.NewGuid();
Task t = new Task(async () => await Get(), cancel.Token);
t.ContinueWith(Complete);
if (tasks.TryAdd(id, t))
{
t.Start();
}
else
{
//another thread is stopping stuff dont start new tasks
}
t.Wait(); //expected to wait for the get function to complete
Console.WriteLine("end test");
}
public async Task Get()
{
Console.WriteLine("start task");
await Task.Delay(10000);
Console.WriteLine("end task");
}
public void Complete(Task t)
{
Console.WriteLine("Complete");
}
}
}
output:
start task
end test
Complete
expected output:
start task
end task
Complete
end test
Update: It appears there is no way to Create a new Task which won't immediately start or complete immediately on Task.Start?
To start a task in C#, follow any of the below given ways. Use a delegate to start a task. Task t = new Task(delegate { PrintMessage(); }); t. Start();
When the await operator is applied to the operand that represents an already completed operation, it returns the result of the operation immediately without suspension of the enclosing method. The await operator doesn't block the thread that evaluates the async method.
The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete. await can only be used inside an async method.
Your delegate is async void. async void-methods are fire and forget.
See first point of Summary of Patterns and Anti-Patterns: http://rarcher.azurewebsites.net/Post/PostContent/31
Maybe you can do something like that:
[TestFixture]
public class FIXTURENAMETests {
[Test]
public async Task NAME() {
var tcs = new TaskCompletionSource<bool>();
Task t = LongRunningStuff(tcs);
if (CanInsertInDictionary(t)) {
tcs.SetResult(true);
} else {
tcs.SetException(new Exception());
}
Trace.WriteLine("waiting for end");
try {
await t;
}
catch (Exception exception) {
Trace.WriteLine(exception);
}
Trace.WriteLine("end all");
}
private bool CanInsertInDictionary(Task task) {
return true;
}
private async Task LongRunningStuff(TaskCompletionSource<bool> tcs) {
Trace.WriteLine("start");
try {
await tcs.Task;
}
catch (Exception) {
return;
}
Trace.WriteLine("do long running stuff");
await Task.Delay(10000);
Trace.WriteLine("end");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With