Я хочу перечислить все текущие потоки, но не используя класс List<>
. Я хочу динамически наблюдать за потоками. Как я могу это сделать?
Получить список тем
Ответ 1
using System.Diagnostics;
ProcessThreadCollection currentThreads = Process.GetCurrentProcess().Threads;
foreach (ProcessThread thread in currentThreads)
{
// Do whatever you need
}
Ответ 2
Способ 1. Получение потоков ОС
Получает список потоков ОС:
ProcessThreadCollection currentThreads = Process.GetCurrentProcess().Threads;
foreach (ProcessThread thread in currentThreads)
{
}
Способ 2: Получить управляемые потоки
Управляемые потоки располагаются поверх потоков ОС. Идентификаторы различны, и теоретически более чем один управляемый поток может сидеть поверх одного потока ОС (хотя я фактически этого не наблюдал).
Оказывается, получение управляемых потоков сложнее, чем это действительно должно быть.
Метод 2.1: Простой код для получения управляемых потоков
- Отметьте Microsoft.Diagnostics.Runtime на GitHub.
- Установите пакет NuGet Диагностика CLR-памяти (ClrMD).
Затем вы можете использовать указанный пакет NuGet для присоединения к вашему собственному процессу и прочитать управляемые потоки:
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)
{
}
}
Метод 2.2: пример поиска управляемых потоков по трассировке стека
К сожалению, я не смог найти способ поиска по списку потоков по имени потока.
Однако все не потеряно: вот пример того, как создать управляемый поток, а затем найти его, выполнив поиск по кадрам стека для соответствия в пространстве имен, а затем распечатайте его свойства:
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}:\n", thread.ManagedThreadId, thread.OSThreadId, thread.IsAlive, thread.IsBackground);
Console.Write("- Stack frames related namespace '{0}':\n", startOfThisNamespace);
foreach (var s in stackframesRelatedToUs)
{
Console.Write(" - StackFrame: {0}\n", s.Method.ToString());
}
}
}
}
}
Вы также можете найти правильное совпадение, сохранив ManagedThreadId
в созданном вами потоке, а затем ищем этот же идентификатор в runtime.Threads
.
Тестирование
Протестировано со всеми комбинациями:
- Visual Studio 2015 SP1
- .NET 4.5
- .NET 4.6.0
- .NET 4.6.1
- С# 5.0
- С# 6.0
Ссылки
См. ClrMd генерирует исключение при создании среды выполнения.