'Visual Studio\Debug\Windows\Tasks\Parent - empty values
It says here (docs.microsoft.com):
Parent: The ID of the task that created this task. If this is blank, the task has no parent. This is only applicable for managed programs.
It says here (docs.microsoft.com):
A child task (or nested task) is a System.Threading.Tasks.Task instance that is created in the user delegate of another task, which is known as the parent task.
I made a simple example After a few seconds, I pause and see that all the values in the parent field are empty.
Question: What code do I need to write to see the filled parent fields in the specified debug window?
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
void MyMethod()
{
Console.WriteLine(Task.CurrentId);
Task.Run(MyMethod);
Thread.Sleep(10000);
}
MyMethod();
}
}
}
or
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
void MyMethod()
{
Console.WriteLine(Task.CurrentId);
new Task(MyMethod, TaskCreationOptions.AttachedToParent).Start();
Thread.Sleep(10000);
}
MyMethod();
}
}
}
Solution 1:[1]
Disclaimer: I'm working on a MacBook so I'm using Visual Studio 2022 for Mac Preview, which does not support Tasks window (yet). So, I couldn't test my sample application
As I said in the comments section the you should explicitly define parent-child relationship between tasks otherwise they are just nested tasks.
- In the former case if one of the child tasks fails then the parent will fail as well
- In the latter case if one of the inner tasks fails then the outer will not fail
Rather than creating an infinite recursion I would suggest to create a sample application which simulates Task.WhenAll
var rnd = new Random();
var ids = Enumerable.Range(0, 4);
var whenAll = Task.Factory.StartNew(() =>
{
foreach (var id in ids)
{
var child = Task.Factory.StartNew((taskId) =>
{
Console.WriteLine($"Child task '{taskId}' is started");
Thread.Sleep(5000 + rnd.Next() % 1000);
Console.WriteLine($"Child task '{taskId}' is finished");
}, id, TaskCreationOptions.AttachedToParent);
}
});
await whenAll;
Console.WriteLine("Finished");
One possible output:
Child task '0' is started
Child task '1' is started
Child task '3' is started
Child task '1' is finished
Child task '3' is finished
Child task '0' is finished
Child task '2' is finished
Finished
Task.Factory.Start instead of Task.Run
Please note that I've used Task.Factory.Start to create the parent task. The reason for this is because the Task.Run is equivalent of this:
Task.Factory.StartNew(action,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
As you can see it explicitly defines that it denies attaching child tasks. So, it will not wait to its child tasks to finish.
In case of Task.Run there is no overload which anticipates TaskCreationOptions parameter.
Debugging
Pause the application after all child tasks have reported that they are started. At this point the Parent column should be populated on the child task rows with the parent's task id.
UPDATE #1: I/O bound example
In the above example the child tasks were CPU-bound. Here is an example for I/O bound.
var client = new HttpClient();
var urls = new[]
{
"https://httpstat.us/200?sleep=5000",
"https://httpstat.us/200?sleep=4000",
"https://httpstat.us/200?sleep=4500",
"https://httpstat.us/200?sleep=3000",
};
async Task Get(string url)
{
Console.WriteLine($"Request to '{url}'");
await client.GetAsync(url);
Console.WriteLine($"Response from '{url}'");
};
var whenAll = Task.Factory.StartNew(() =>
{
foreach (var url in urls)
{
var child = Task.Factory.StartNew(
(requestUrl) => Get((string)requestUrl),
url,
TaskCreationOptions.AttachedToParent)
.Unwrap();
}
});
await whenAll;
Console.WriteLine("Finished");
- Since
StartNewdoes not have overload which can accept aFunc<Task>that's why here theStartNewreturns aTask<Task> - In order to flatten / unfold that we need to call
Unwrap
One possible output
Request to 'https://httpstat.us/200?sleep=5000'
Request to 'https://httpstat.us/200?sleep=3000'
Request to 'https://httpstat.us/200?sleep=4000'
Request to 'https://httpstat.us/200?sleep=4500'
Response from 'https://httpstat.us/200?sleep=3000'
Response from 'https://httpstat.us/200?sleep=4000'
Response from 'https://httpstat.us/200?sleep=4500'
Response from 'https://httpstat.us/200?sleep=5000'
Finished
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |

