【问题标题】:How to determine which CPU a thread runs on?如何确定线程在哪个 CPU 上运行?
【发布时间】:2018-09-12 23:32:10
【问题描述】:

有没有办法确定给定线程在哪个 CPU 上运行? 最好在 C# 中,但 C++ 会这样做。

.NET Process 和 ProcessThread 类似乎不提供此信息。

ETA 说明:

我们正在开发一个服务器应用程序,用于处理 http 多播流并生成多个视频编码器。这在具有 12 个物理内核的系统上运行,从而产生 24 个逻辑 CPU(超线程)。通过 TaskManager 和 ProcessExplorer,我们验证了我们生成的进程均匀分布在逻辑 CPU 上。然而,我们在一个 CPU 上看到了很多(内核?)活动,这些活动通过消耗异常多的 CPU 时间而产生干扰。我们正在尝试确定哪些进程/线程正在此特定 CPU 上运行。 TaskManager 和 ProcessExplorer 似乎都没有提供该信息。如果有,请说明如何获得此类信息。

否则,我们正在考虑编写自己的工具来获取此信息。这就是我们需要帮助的地方。

我们知道如何更改线程关联性(并且我们知道无法保证线程将与任何 CPU 保持关联,尽管在这种特殊情况下,占用 CPU 的线程仍仅与一个 CPU 关联) ,但为了做到这一点,我们需要首先确定需要重定位哪个进程/线程。这是这个问题的唯一目标。

我希望这有助于澄清问题。

【问题讨论】:

  • 你想用这些信息解决什么问题?
  • 只有内核知道。所以你需要在内核模式下编程。在 MSDN 上查找内核 API。
  • 如果一个线程在不同时间运行在许多不同的 CPU 上,你希望它做什么?
  • 我们在一个有 12 个内核的系统上运行一个复杂的应用程序。出于某些原因,我们需要找出仅在一个内核上看到 CPU 使用率飙升的情况。我们想找出哪些线程(以及哪些进程或服务)正在这个特定的核心上运行。我们不知道有一种工具可以提供这些信息并考虑编写我们自己的工具。
  • 无效的问题。这与哪个 CPU 无关——这与为什么这个所谓的多线程程序不使用超过一个 CPU 的原因有关。在适当的分析器中检查线程负载,您可能会发现您遇到了处理瓶颈。 Visual Studio 有用于此类分析的 ap profiler。

标签: c# c++ multithreading


【解决方案1】:

来自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 做同样的事情。

【讨论】:

  • 此外,线程会四处移动,因此即使您得到答案,在您尝试检查某些内容时也不一定有效。
  • 是的,Process 和 ProcessThread 上的 ProcessorAffinity 属性是我的第一个希望,但正如你所指出的,我无法获得它......
  • @TomTom:是的,它们可以移动,但在我们的例子中,快照已经提供了有价值的信息。
  • @Harald 如果您设置处理器亲和性,您就会知道它是什么。它是您正在使用的第三方组件,您需要了解其亲和性吗?
  • @Harald 您是否尝试过使用第三方分析应用程序,例如 JetBrains dotTrace(强烈推荐)或 ANTS Profiler? jetbrains.com/profiler
【解决方案2】:

这不可能以持续可靠的方式进行。操作系统任务调度程序优化线程并在可用 CPU 内核之间分配负载。一般情况下,线程可以在任何 CPU 上执行。此外,通过上下文切换,它还可以改变它的 CPU。

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

【讨论】:

  • 虽然技术上是正确的,但您的回答缺少了非常重要的一点。了解您当前的 CPU 可以通过分桶共享资源来显着减少争用。是的,在极少数情况下,您会被打断并转移到其他核心。这意味着仍然需要同步。但是性能结果是无法比拟的。
  • @KirillKobelev 你能给我一些参考吗?我可以看到它在低级别上工作,但不确定如何从应用程序中管理它。你说的是 NUMA 吗?
  • 想想int cnt[num_cores]; InterlockedIncrement(cnt[GetCurrCore()]); 与只有一个计数器的简单版本的性能。
  • 类似的分片(如上所述)可以在托管线程 ID 上完成。无论如何,我来到这个问题想知道是否也可以在(启动)CPU核心#上完成。不太容易猜。. 在某些情况下,按托管 ID 进行分片对于显着减少锁争用仍然非常有用。
【解决方案3】:

从 Vista/Server2003 开始​​,您可以 PInvoke GetCurrentProcessorNumber() Windows API 方法 (https://docs.microsoft.com/en-gb/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getcurrentprocessornumber)。

显然仅限 Windows,如果您打算支持其他平台,则不理想。

我不确定 OP 的用例是否理想,但在尝试创建保证在系统内唯一的时间戳时它可能是明智/有用的,即使所有处理器都在完全相同的时间计算一个.

【讨论】:

    猜你喜欢
    • 2021-03-11
    • 2013-02-27
    • 1970-01-01
    • 2016-08-28
    • 2011-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多