如何确定一个线程运行在哪个CPU上?

18
有没有办法确定一个线程在哪个CPU上运行? 最好用C#,但是C++也可以。 .NET的Process和ProcessThread类似乎没有提供这个信息。
预计时间澄清: 我们正在开发一个处理http多播流并生成多个视频编码器的服务器应用程序。这在拥有12个物理核心的系统上运行,导致24个逻辑CPU(超线程)。通过TaskManager和ProcessExplorer,我们已经验证了我们生成的进程均匀地分布在逻辑CPU上。然而,我们看到只有一个CPU上有大量的(内核?)活动,导致异常消耗CPU时间。我们正在尝试确定运行在这个特定CPU上的哪些进程/线程。TaskManager和ProcessExplorer都不提供此信息。如果它们提供,请解释如何获取此类信息。 否则,我们正在考虑编写自己的工具以获取此信息。这就是我们需要帮助的地方。 我们知道如何更改线程的关联(并且我们知道没有保证线程将保持与任何CPU相关联,尽管在这种特殊情况下,占用CPU的线程仅与一个CPU相关联),但是为了这样做,我们需要首先确定需要重新定位的进程/线程。这是这个问题唯一的目标。 我希望这有助于澄清问题。

8
你想通过这些信息解决什么问题? - Cody Gray
2
如果一个线程在不同的时间运行在许多不同的CPU上,你希望它做什么? - Jon Skeet
4
我们正在一个拥有12个核心的系统上运行复杂的应用程序。由于某些原因,我们发现只有一个核心的CPU使用率会突然升高。我们想找出在这个特定核心上运行的线程(以及由此运行的进程或服务)。我们不知道是否有工具可以提供这种信息,正在考虑自己编写一个工具。 - Harald
1
这不是一个有效的问题。这不是关于哪个CPU的问题,而是为什么这个被认为是多线程程序的东西没有使用超过一个CPU。在适当的分析器中检查线程负载,你可能会发现你有一个处理瓶颈。Visual Studio有一个这种类型分析的分析器。 - TomTom
尝试将输出导向dev\null。我想知道内核工作是否涉及TCP/IP协议栈。 - Aron
显示剩余8条评论
3个回答

4

MSDN得知,使用ProcessThread.ProcessorAffinity属性可以设置线程亲和性,但无法获取。默认情况下,线程没有亲和性(可以在任何处理器上运行)。

using System;
using System.Diagnostics;

namespace ProcessThreadIdealProcessor
{
    class Program
    {
        static void Main(string[] args)
        {
            // Make sure there is an instance of notepad running.
            Process[] notepads = Process.GetProcessesByName("notepad");
            if (notepads.Length == 0)
                Process.Start("notepad");
            ProcessThreadCollection threads;
            //Process[] notepads;
            // Retrieve the Notepad processes.
            notepads = Process.GetProcessesByName("Notepad");
            // Get the ProcessThread collection for the first instance
            threads = notepads[0].Threads;
            // Set the properties on the first ProcessThread in the collection
            threads[0].IdealProcessor = 0;
            threads[0].ProcessorAffinity = (IntPtr)1;
        }
    }
}

类似地,Thread.SetProcessorAffinity也是这样做的。

1
此外,线程是会移动的,因此即使您得到了答案,在您尝试检查某些内容时它也不一定有效。 - TomTom
是的,Process和ProcessThread上的ProcessorAffinity属性是我最初的希望,但正如你指出的那样,我无法获取它... - Harald
@TomTom:是的,它们可以被移动,但在我们的情况下,快照已经提供了有价值的信息。 - Harald
是的,很可能会发生这种情况。我们正在开发一个服务器应用程序,该程序处理多播流并生成多个视频编码器。我们生成的进程均匀分布在各个核心上,但是我们发现只有一个核心出现了大量(内核?)活动,这会干扰其他进程。我们需要确定具体是什么干扰了其他进程,以便进行修复。 - Harald
2
@Harald,你尝试过使用第三方性能分析工具,比如 JetBrains dotTrace(强烈推荐)或 ANTS Profiler 吗?http://www.jetbrains.com/profiler/ - Dr. Andrew Burnett-Thompson
显示剩余2条评论

2

在连续可靠的方式下,这是不可能做到的。操作系统任务调度程序会优化线程并在可用的CPU核心之间分配负载。一般情况下,线程可以在任何CPU上执行。此外,通过上下文切换,它也可以更改所在的CPU。

如果您需要精确定位特定的线程或进程,则只能分配其关联性,因此您可以合理地希望该进程/线程将在特定的逻辑CPU上执行。


1
尽管从技术上讲你的回答是正确的,但它缺少了非常重要的一点。了解你当前的CPU可以通过将共享资源分桶来显著地减少争用。是的,在极少数情况下,你会被中断并移动到其他核心。这意味着仍然需要同步。但性能结果是无法比拟的。 - Kirill Kobelev
@KirillKobelev,你能给我一些参考资料吗?我可以看到它在低级别上运作,但不确定如何从应用程序中管理它。你是在谈论NUMA吗? - oleksii
1
考虑 int cnt[num_cores]; InterlockedIncrement(cnt[GetCurrCore()]); 的性能与只有一个计数器的简单版本相比。 - Kirill Kobelev
类似于上面所解释的分片技术,可以在托管线程 ID 上执行。无论如何,我来到这个问题是想知道是否也可以在(初始化)CPU 核心 # 上执行此操作。看来不是那么容易...通过托管 ID 进行分片在某些情况下仍然非常有用,可以显著减少锁争用。 - user2864740

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接