有没有办法以独立于平台的方式从 C/C++ 中确定一台机器有多少个内核?如果不存在这样的东西,那么如何确定每个平台(Windows/*nix/Mac)呢?
20 回答
C++11
#include <thread>
//may return 0 when not able to detect
const auto processor_count = std::thread::hardware_concurrency();
参考:std::thread::hardware_concurrency
在 C++11 之前的 C++ 中,没有可移植的方式。相反,您需要使用以下一种或多种方法(由适当的#ifdef
行保护):
Win32
SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); int numCPU = sysinfo.dwNumberOfProcessors;
Linux、Solaris、AIX 和 Mac OS X >=10.4(即 Tiger 以后)
int numCPU = sysconf(_SC_NPROCESSORS_ONLN);
FreeBSD、MacOS X、NetBSD、OpenBSD 等。
int mib[4]; int numCPU; std::size_t len = sizeof(numCPU); /* set the mib for hw.ncpu */ mib[0] = CTL_HW; mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU; /* get the number of CPUs from the system */ sysctl(mib, 2, &numCPU, &len, NULL, 0); if (numCPU < 1) { mib[1] = HW_NCPU; sysctl(mib, 2, &numCPU, &len, NULL, 0); if (numCPU < 1) numCPU = 1; }
HPUX
int numCPU = mpctl(MPC_GETNUMSPUS, NULL, NULL);
IRIX
int numCPU = sysconf(_SC_NPROC_ONLN);
Objective-C (Mac OS X >=10.5 或 iOS)
NSUInteger a = [[NSProcessInfo processInfo] processorCount]; NSUInteger b = [[NSProcessInfo processInfo] activeProcessorCount];
此功能是 C++11 标准的一部分。
#include <thread>
unsigned int nthreads = std::thread::hardware_concurrency();
对于较旧的编译器,您可以使用Boost.Thread库。
#include <boost/thread.hpp>
unsigned int nthreads = boost::thread::hardware_concurrency();
无论哪种情况,hardware_concurrency()
根据 CPU 内核和超线程单元的数量,返回硬件能够同时执行的线程数。
如果您有汇编语言访问权限,则可以使用 CPUID 指令来获取有关 CPU 的各种信息。它可以在操作系统之间移植,但您需要使用制造商特定的信息来确定如何查找内核数量。这是一份描述如何在英特尔芯片上执行此操作的文档,该文档的第 11 页描述了 AMD 规范。
(几乎)c代码中的平台无关函数
#ifdef _WIN32
#include <windows.h>
#elif MACOS
#include <sys/param.h>
#include <sys/sysctl.h>
#else
#include <unistd.h>
#endif
int getNumCores() {
#ifdef WIN32
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
#elif MACOS
int nm[2];
size_t len = 4;
uint32_t count;
nm[0] = CTL_HW; nm[1] = HW_AVAILCPU;
sysctl(nm, 2, &count, &len, NULL, 0);
if(count < 1) {
nm[1] = HW_NCPU;
sysctl(nm, 2, &count, &len, NULL, 0);
if(count < 1) { count = 1; }
}
return count;
#else
return sysconf(_SC_NPROCESSORS_ONLN);
#endif
}
在 Linux 上,您可以读取 /proc/cpuinfo 文件并计算内核数。
请注意,“核心数”可能不是一个特别有用的数字,您可能需要对其进行更多限定。您想如何计算多线程 CPU,例如 Intel HT、IBM Power5 和 Power6,以及最著名的 Sun 的 Niagara/UltraSparc T1 和 T2?或者更有趣的是,MIPS 1004k 具有两个级别的硬件线程(管理程序和用户级)......更不用说当您进入支持虚拟机管理程序的系统时会发生什么,其中硬件可能有数十个 CPU,但您的特定操作系统只看到几个。
您可以期望的最好结果是告诉您在本地操作系统分区中拥有的逻辑处理单元的数量。除非您是虚拟机管理程序,否则忘记查看真正的机器。今天这个规则的唯一例外是在 x86 领域,但非虚拟机的终结即将到来......
另一个 Windows 秘诀:使用系统范围的环境变量NUMBER_OF_PROCESSORS
:
printf("%d\n", atoi(getenv("NUMBER_OF_PROCESSORS")));
您可能无法以独立于平台的方式获得它。Windows 你得到处理器的数量。
Windows(x64 和 Win32)和 C++11
共享单个处理器内核的逻辑处理器组的数量。(使用GetLogicalProcessorInformationEx,请参阅GetLogicalProcessorInformation以及)
size_t NumberOfPhysicalCores() noexcept {
DWORD length = 0;
const BOOL result_first = GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &length);
assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
std::unique_ptr< uint8_t[] > buffer(new uint8_t[length]);
const PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info =
reinterpret_cast< PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX >(buffer.get());
const BOOL result_second = GetLogicalProcessorInformationEx(RelationProcessorCore, info, &length);
assert(result_second != FALSE);
size_t nb_physical_cores = 0;
size_t offset = 0;
do {
const PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX current_info =
reinterpret_cast< PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX >(buffer.get() + offset);
offset += current_info->Size;
++nb_physical_cores;
} while (offset < length);
return nb_physical_cores;
}
请注意,NumberOfPhysicalCores
恕我直言,实现远非微不足道(即“使用GetLogicalProcessorInformation
或GetLogicalProcessorInformationEx
”)。相反,如果阅读MSDN上的文档(显式存在GetLogicalProcessorInformation
和隐式存在),则相当微妙。GetLogicalProcessorInformationEx
逻辑处理器的数量。(使用GetSystemInfo)
size_t NumberOfSystemCores() noexcept {
SYSTEM_INFO system_info;
ZeroMemory(&system_info, sizeof(system_info));
GetSystemInfo(&system_info);
return static_cast< size_t >(system_info.dwNumberOfProcessors);
}
请注意,这两种方法都可以轻松转换为 C/C++98/C++03。
与 C++ 无关,但在 Linux 上我通常这样做:
grep processor /proc/cpuinfo | wc -l
对于像 bash/perl/python/ruby 这样的脚本语言很方便。
有关 OS X 的更多信息:sysconf(_SC_NPROCESSORS_ONLN)
仅适用于 >= 10.5 的版本,而不是 10.4。
另一种选择是在HW_AVAILCPU/sysctl()
>= 10.2 版本上可用的 BSD 代码。
Windows Server 2003 及更高版本允许您利用 GetLogicalProcessorInformation 函数
据我所知,在 linux 上最好的编程方式是使用
sysconf(_SC_NPROCESSORS_CONF)
或者
sysconf(_SC_NPROCESSORS_ONLN)
这些不是标准的,但在我的 Linux 手册页中。
hwloc (http://www.open-mpi.org/projects/hwloc/) 值得一看。虽然需要将另一个库集成到您的代码中,但它可以提供有关您的处理器的所有信息(内核数量、拓扑结构等)
在 Linux 上,使用它可能不安全,_SC_NPROCESSORS_ONLN
因为它不是 POSIX 标准的一部分,而且sysconf手册也有同样的规定。所以有一种_SC_NPROCESSORS_ONLN
可能不存在:
These values also exist, but may not be standard.
[...]
- _SC_NPROCESSORS_CONF
The number of processors configured.
- _SC_NPROCESSORS_ONLN
The number of processors currently online (available).
一个简单的方法是阅读/proc/stat
或/proc/cpuinfo
计算它们:
#include<unistd.h>
#include<stdio.h>
int main(void)
{
char str[256];
int procCount = -1; // to offset for the first entry
FILE *fp;
if( (fp = fopen("/proc/stat", "r")) )
{
while(fgets(str, sizeof str, fp))
if( !memcmp(str, "cpu", 3) ) procCount++;
}
if ( procCount == -1)
{
printf("Unable to get proc count. Defaulting to 2");
procCount=2;
}
printf("Proc Count:%d\n", procCount);
return 0;
}
使用/proc/cpuinfo
:
#include<unistd.h>
#include<stdio.h>
int main(void)
{
char str[256];
int procCount = 0;
FILE *fp;
if( (fp = fopen("/proc/cpuinfo", "r")) )
{
while(fgets(str, sizeof str, fp))
if( !memcmp(str, "processor", 9) ) procCount++;
}
if ( !procCount )
{
printf("Unable to get proc count. Defaulting to 2");
procCount=2;
}
printf("Proc Count:%d\n", procCount);
return 0;
}
在 shell 中使用 grep 的相同方法:
grep -c ^processor /proc/cpuinfo
或者
grep -c ^cpu /proc/stat # subtract 1 from the result
OS X 替代方案:根据文档,前面描述的基于 [[NSProcessInfo processInfo] processorCount] 的解决方案仅在 OS X 10.5.0 上可用。对于早期版本的 OS X,请使用 Carbon 函数 MPProcessors()。
如果您是 Cocoa 程序员,请不要被 Carbon 的事实吓到。您只需要将 Carbon 框架添加到您的 Xcode 项目中,MPProcessors() 就可以使用了。
对于 Win32:
GetSystemInfo() 获取逻辑处理器的数量,使用 GetLogicalProcessorInformationEx() 获取物理处理器的数量。
#include <stdint.h>
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/sysctl.h>
uint32_t num_physical_cores(void)
{
uint32_t num_cores = 0;
size_t num_cores_len = sizeof(num_cores);
sysctlbyname("hw.physicalcpu", &num_cores, &num_cores_len, 0, 0);
return num_cores;
}
#elif defined(__linux__)
#include <unistd.h>
#include <stdio.h>
uint32_t num_physical_cores(void)
{
uint32_t lcores = 0, tsibs = 0;
char buff[32];
char path[64];
for (lcores = 0;;lcores++) {
FILE *cpu;
snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%u/topology/thread_siblings_list", lcores);
cpu = fopen(path, "r");
if (!cpu) break;
while (fscanf(cpu, "%[0-9]", buff)) {
tsibs++;
if (fgetc(cpu) != ',') break;
}
fclose(cpu);
}
return lcores / (tsibs / lcores);
}
#else
#error Unrecognized operating system
#endif
这应该返回系统上的物理核心数。这与大多数答案提供的逻辑核心数量不同。如果您正在寻找不执行阻塞 I/O 并且不休眠的线程池的大小,那么您希望使用物理内核的数量,而不是逻辑(超线程)内核的数量。
此答案仅提供 Linux 和 BSD 的实现。
您也可以在 .net 中使用 WMI,但是您依赖于运行的 wmi 服务等。有时它可以在本地工作,但是当在服务器上运行相同的代码时会失败。我相信这是一个名称空间问题,与您正在阅读其值的“名称”有关。