Вам нужно будет найти способ сделать ваш параллельный алгоритм несколько независимым от количества потоков.
Самый простой способ - сделать что-то вроде:
int tid = omp_get_thread_num();
int n_threads = omp_get_num_threads();
for (int i = tid; i < num_steps; i += n_threads) {
// ...
}
Таким образом, работа распределяется по всем потокам независимо от количества потоков.
Если было 3 темы и 9 шагов:
- Поток 0 будет выполнять шаги 0, 3, 6
- Поток 1 будет выполнять шаги 1, 4, 7
- Поток 2 будет выполнять шаги 2, 5, 8
Это работает, но не идеально, если каждый поток обращается к данным из некоторого общего массива. Лучше, если потоки обращаются к разделам данных поблизости для locality целей.
В этом случае вы можете разделить количество шагов на количество потоков и дать каждому потоку непрерывный набор задач, например:
int tid = omp_get_thread_num();
int n_threads = omp_get_num_threads();
int steps_per_thread = num_steps / n_threads;
int start = tid * steps_per_thread;
int end = start + steps_per_thread;
for (int i = start; i < end; i++) {
// ...
}
Теперь 3 потока, выполняющие 9 шагов, выглядят так:
- Тема 0 выполняет шаги 0, 1, 2
- Тема 1 выполняет шаги 3, 4, 5
- Нить 2 выполняет шаги 6, 7, 8
Этот подход на самом деле наиболее вероятен при использовании #pragma omp for
. В большинстве случаев компилятор просто делит задачи в соответствии с количеством потоков и назначает каждому потоку раздел.
Таким образом, учитывая набор из 2 потоков и 100 итераций для цикла, компилятор, скорее всего, даст итерации 0-49 для потока 0 и итерации 50-99 для потока 1.
Обратите внимание, что если число итераций не делится поровну на количество потоков, остаток необходимо обработать явно.