Method 1: Get OS Threads
This gets the list of OS threads:
ProcessThreadCollection currentThreads = Process.GetCurrentProcess().Threads;
foreach (ProcessThread thread in currentThreads)
{
}
Method 2: Get Managed Threads
Managed threads sit on top of OS threads. The IDs are different, and in theory, more than one Managed Thread may sit on top of a single OS thread (although I havn't actually observed this).
It turns out that getting managed threads is trickier than it really should be.
Method 2.1: Simplest code to get Managed Threads
- Check out Microsoft.Diagnostics.Runtime on GitHub.
- Install NuGet package CLR Memory Diagnostics (ClrMD).
You can then use said NuGet package to attach to your own process, and read the managed threads out:
using Microsoft.Diagnostics.Runtime;
using (DataTarget target = DataTarget.AttachToProcess(
Process.GetCurrentProcess().Id, 5000, AttachFlag.Passive))
{
ClrRuntime runtime = target.ClrVersions.First().CreateRuntime();
foreach (ClrThread thread in runtime.Threads)
{
}
}
Method 2.2: Example of how to search through managed threads by stack trace
Unfortunately, I couldn't find any way to search through the list of threads by the thread name.
However, all is not lost: here is an example of how to create a managed thread, then find it by searching through the stack frames for a match on the namespace, then print out its properties:
namespace MyTest
{
int managedThreadId = 0;
var task = Task.Run(
() =>
{
// Unfortunately, cant see "Testing" anywhere in result returned
// from NuGet package ClrMD ...
Thread.CurrentThread.Name = "Testing";
Thread.Sleep(TimeSpan.FromDays(1));
});
// ... so we look for our thread by the first word in this namespace.
string startOfThisNamespace = this.GetType().Namespace.ToString().Split('.')[0]; // Is "MyTest".
using (DataTarget target = DataTarget.AttachToProcess(Process.GetCurrentProcess().Id, 5000, AttachFlag.Passive))
{
ClrRuntime runtime = target.ClrVersions.First().CreateRuntime();
foreach (ClrThread thread in runtime.Threads)
{
IList<ClrStackFrame> stackFrames = thread.StackTrace;
List<ClrStackFrame> stackframesRelatedToUs = stackFrames
.Where(o => o.Method != null && o.Method.ToString().StartsWith(startOfThisNamespace)).ToList();
if (stackframesRelatedToUs.Count > 0)
{
Console.Write("ManagedThreadId: {0}, OSThreadId: {1}, Thread: IsAlive: {2}, IsBackground: {3}:
", thread.ManagedThreadId, thread.OSThreadId, thread.IsAlive, thread.IsBackground);
Console.Write("- Stack frames related namespace '{0}':
", startOfThisNamespace);
foreach (var s in stackframesRelatedToUs)
{
Console.Write(" - StackFrame: {0}
", s.Method.ToString());
}
}
}
}
}
You can also find the correct match by saving ManagedThreadId
within the thread that you create, then looking for this same ID in runtime.Threads
.
Testing
Tested with all combinations of:
- Visual Studio 2015 SP1
- .NET 4.5
- .NET 4.6.0
- .NET 4.6.1
- C# 5.0
- C# 6.0
References
See ClrMd throws exception when creating runtime.