Как программно определить количество ядер процессора на C++ (кроссплатформенное решение)?
Решение на C++17 с использованием std::thread::hardware_concurrency
В современном C++ (начиная с C++11) есть стандартный способ получить количество аппаратных потоков — функция std::thread::hardware_concurrency(). Она возвращает число аппаратных потоков (логических ядер), которые могут выполняться одновременно. Это кроссплатформенное решение, которое работает на Windows, Linux и macOS.
#include <iostream>
#include <thread>
int main() {
unsigned int logical_cores = std::thread::hardware_concurrency();
std::cout << "Логических ядер: " << logical_cores << std::endl;
return 0;
}
Важное замечание: Если функция не может определить количество ядер, она возвращает 0. Всегда проверяйте это значение перед использованием:
unsigned int cores = std::thread::hardware_concurrency();
if (cores == 0) {
cores = 1; // или другое значение по умолчанию
}
Как получить количество физических ядер?
Стандартный C++ не предоставляет способа различить физические и логические ядра. Это особенность аппаратуры и операционной системы. Однако вы можете использовать платформозависимые API в сочетании с условной компиляцией, но сделать это "чище", чем в вашем примере:
#include <iostream>
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
int getPhysicalCores() {
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
}
#elif defined(__linux__)
#include <unistd.h>
#include <fstream>
#include <string>
int getPhysicalCores() {
// Читаем /proc/cpuinfo, считаем уникальные "core id"
std::ifstream cpuinfo("/proc/cpuinfo");
std::string line;
int physical_cores = 0;
int last_core_id = -1;
while (std::getline(cpuinfo, line)) {
if (line.find("core id") != std::string::npos) {
int core_id = std::stoi(line.substr(line.find(':') + 1));
if (core_id != last_core_id) {
physical_cores++;
last_core_id = core_id;
}
}
}
return physical_cores > 0 ? physical_cores : 1;
}
#elif defined(__APPLE__)
#include <sys/sysctl.h>
int getPhysicalCores() {
int count;
size_t size = sizeof(count);
sysctlbyname("hw.physicalcpu", &count, &size, nullptr, 0);
return count > 0 ? count : 1;
}
#else
int getPhysicalCores() {
return 1; // fallback
}
#endif
int main() {
std::cout << "Физических ядер: " << getPhysicalCores() << std::endl;
return 0;
}
Рекомендации по выбору количества потоков
Для большинства задач оптимальное количество потоков равно std::thread::hardware_concurrency() или hardware_concurrency() - 1 (чтобы оставить один поток для ОС). Если вы обрабатываете данные и боитесь перегрузки кэша, попробуйте использовать hardware_concurrency() / 2 как начальное значение и профилируйте производительность.
Помните: не всегда больше потоков = быстрее. Из-за накладных расходов на переключение контекста и синхронизацию, иногда 4 потока на 8-ядерном процессоре работают быстрее, чем 8.
<<Альтернативный подход: использование библиотеки Boost
Если вы не хотите писать платформозависимый код, но нужна более точная информация о процессоре, чем дает std::thread::hardware_concurrency, рассмотрите библиотеку Boost. Она предоставляет кроссплатформенный интерфейс для получения информации об оборудовании.
#include <boost/compute/system.hpp>
#include <iostream>
int main() {
// Количество логических ядер
unsigned int logical = boost::thread::hardware_concurrency();
// Получить количество физических ядер можно через Boost.Compute
auto device = boost::compute::system::default_device();
unsigned int physical = device.compute_units();
std::cout << "Логических ядер: " << logical << std::endl;
std::cout << "Физических ядер (compute units): " << physical << std::endl;
return 0;
}
Плюсы:
- Единый API для всех платформ
- Доступ к дополнительной информации (кэш, частота, архитектура)
- Хорошо протестирован и поддерживается
Минусы:
- Требует установки Boost (увеличивает размер проекта)
- Для простых задач может быть избыточным
Если ваш проект уже использует Boost, это отличный вариант. В противном случае, для большинства задач достаточно std::thread::hardware_concurrency() — это стандартный, современный и кроссплатформенный подход.