Как обеспечить, чтобы std::thread создавался в многоядерном режиме?

Я использую Visual Studio 2012. У меня есть модуль, где я должен прочитать огромный набор файлов с жесткого диска после прохождения их соответствующих путей через XML. Для этого я делаю

std::vector<std::thread> m_ThreadList;

В цикле while я возвращаю новую нить в этот вектор, что-то вроде

m_ThreadList.push_back(std::thread(&MyClass::Readfile, &MyClassObject, filepath,std::ref(polygon)));

Мои знания по многопоточности в C++11 ограничены. Вопрос, который я здесь задаю, заключается в том, как создать поток на конкретном ядре? Я знаю о Parallel_for и Parallel_for_each в vs2012, которые оптимально используют ядра. Но есть ли способ сделать это с помощью стандартного C++11?

3 ответа

Решение

Как указано в других комментариях, вы не можете создать поток "на конкретном ядре", так как C++ не знает таких архитектурных деталей. Более того, в большинстве случаев операционная система сможет достаточно хорошо управлять распределением потоков между ядрами / процессорами.

Тем не менее, существуют случаи, когда принудительное распределение потоков между ядрами может быть полезным для производительности. В качестве примера, принудительно выполняя поток на одном конкретном ядре, можно минимизировать перемещение данных между различными кэшами процессора (что может иметь решающее значение для производительности в определенных сценариях, связанных с памятью).

Если вы хотите пойти по этому пути, вам придется изучить подпрограммы для конкретной платформы. Например, для GNU/ Linux с потоками POSIX вы хотите pthread_setaffinity_np()во FreeBSD cpuset_setaffinity()в винде SetThreadAffinityMask(), так далее.

У меня есть некоторые соответствующие фрагменты кода здесь, если вы заинтересованы:

http://gitorious.org/piranhapp0x/mainline/blobs/master/src/thread_management.cpp

Я совершенно уверен, что сродство ядра не включено в std::thread. Предполагается, что ОС вполне способна максимально эффективно использовать доступные ядра. Во всех случаях, кроме самых крайних, вы не собираетесь опровергать решение ОС, поэтому предположение справедливо.

Если вы пойдете по этому пути, то вам придется добавить некоторые решения в ваш код, чтобы учесть архитектуру машины, чтобы убедиться, что ваше решение лучше, чем ОС на каждой машине, на которой вы работаете. Это требует много усилий! Для начала вы захотите ограничить количество потоков в соответствии с количеством ядер на компьютере. И у вас нет никаких знаний о том, что еще происходит в машине; ОС делает!

Вот почему существуют пулы потоков. По умолчанию они имеют столько потоков, сколько имеется ядер, автоматически настраиваемых языковой средой выполнения. AFAIK C++11 не имеет ни одного из них. Итак, одна хорошая вещь, которую вы можете сделать, чтобы получить оптимальную производительность, - это узнать, сколько ядер есть, и ограничить количество потоков, которые у вас есть, этим числом. В противном случае, вероятно, лучше всего доверять ОС.

На комментарий Йоахима Пилеборга стоит обратить внимание, если только работа, выполняемая каждым потоком, не перевешивает издержки ввода-вывода.

В качестве краткого обзора потоков в контексте распределения потоков по ядрам:

Большинство современных ОС используют потоки уровня ядра или гибридные. При использовании потоков на уровне ядра ОС "видит" все потоки в каждом процессе; в отличие от потоков пользовательского уровня, которые используются в Java, где ОС видит один процесс и не знает о многопоточности. Теперь, поскольку благодаря многопоточности на уровне ядра ОС может распознавать отдельные потоки процесса и управлять их распределением на заданное ядро, существует вероятность истинного параллелизма - когда несколько потоков одного и того же процесса выполняются на разных ядрах. Вы, как программист, не будете иметь никакого контроля над этим, однако, при использовании std::thread; ОС решает. При использовании многопоточности на уровне пользователя все управление потоками осуществляется на уровне пользователя, а с помощью Java библиотека управляет "диспетчеризацией". В случае гибридной многопоточности используется многопоточность ядра, где каждый поток ядра фактически является набором потоков пользовательского уровня.

Другие вопросы по тегам