获取主题列表

时间:2012-04-25 12:42:09

标签: c# multithreading list

我想列出所有正在运行的线程,但不是使用List<>类。我想动态观察正在运行的线程。我怎么能这样做?

3 个答案:

答案 0 :(得分:49)

using System.Diagnostics;

ProcessThreadCollection currentThreads = Process.GetCurrentProcess().Threads;

foreach (ProcessThread thread in currentThreads)    
{
   // Do whatever you need
}

答案 1 :(得分:48)

方法1:获取操作系统线程

这将获得操作系统线程列表:

ProcessThreadCollection currentThreads = Process.GetCurrentProcess().Threads;

foreach (ProcessThread thread in currentThreads)
{
}

方法2:获取托管线程

托管线程位于OS线程之上。 ID是不同的,理论上,不止一个托管线程可能位于单个操作系统线程之上(尽管我实际上没有观察到这一点)。

事实证明,获取托管线程比实际应该更加棘手。

方法2.1:获取托管线程的最简单代码

  1. 查看Microsoft.Diagnostics.Runtime on GitHub
  2. 安装NuGet包CLR Memory Diagnostics (ClrMD)
  3. 然后,您可以使用所述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中查找相同的ID。

    测试

    使用以下所有组合进行测试:

    • Visual Studio 2015 SP1
    • .NET 4.5
    • .NET 4.6.0
    • .NET 4.6.1
    • C#5.0
    • C#6.0

    参考

    请参阅ClrMd throws exception when creating runtime

答案 2 :(得分:1)

更新了代码以获取使用@Contango 的答案作为基础的所有堆栈跟踪的快照。您仍然需要安装 NuGet 包 CLR Memory Diagnostics (ClrMD)。此代码段还包含用于获取线程名称的额外代码,但如果您只需要堆栈跟踪,则不需要这样做。

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.Diagnostics.Runtime;

namespace CSharpUtils.wrc.utils.debugging
{
    public static class StackTraceAnalysis
    {
        public static string GetAllStackTraces()
        {
            var result = new StringBuilder();
            
            using (var target = DataTarget.CreateSnapshotAndAttach(Process.GetCurrentProcess().Id))
            {
                var runtime = target.ClrVersions.First().CreateRuntime();

                // We can't get the thread name from the ClrThead objects, so we'll look for
                // Thread instances on the heap and get the names from those.    
                var threadNameLookup = new Dictionary<int, string>();
                foreach (var obj in runtime.Heap.EnumerateObjects())
                {
                    if (!(obj.Type is null) && obj.Type.Name == "System.Threading.Thread")
                    {
                        var threadId = obj.ReadField<int>("m_ManagedThreadId");
                        var threadName = obj.ReadStringField("m_Name");
                        threadNameLookup[threadId] = threadName;
                    }
                }

                foreach (var thread in runtime.Threads)
                {
                    threadNameLookup.TryGetValue(thread.ManagedThreadId, out string threadName);
                    result.AppendLine(
                        $"ManagedThreadId: {thread.ManagedThreadId}, Name: {threadName}, OSThreadId: {thread.OSThreadId}, Thread: IsAlive: {thread.IsAlive}, IsBackground: {thread.IsBackground}");
                    foreach (var clrStackFrame in thread.EnumerateStackTrace())
                        result.AppendLine($"{clrStackFrame.Method}");
                }
            }

            return result.ToString();
        }
    }
}