OpenMP: общее количество работающих потоков

Мне нужно знать общее количество потоков, которые было создано моим приложением через OpenMP. К сожалению, функция omp_get_num_threads() работает здесь не, поскольку она дает только количество потоков в текущей команде.

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

Есть ли способ обойти ограничения omp_get_num_threads и получить общее количество запущенных потоков?

Если требуется более подробная информация, рассмотрим следующий псевдокод, который довольно точно моделирует мой рабочий процесс:

function divide_and_conquer(Job job, int total_num_threads):
  if job.is_leaf(): # Recurrence base case.
    job.process()
    return

  left, right = job.divide()

  current_num_threads = omp_get_num_threads()
  if current_num_threads < total_num_threads: # (1)
    #pragma omp parallel num_threads(2)
      #pragma omp section
        divide_and_conquer(left, total_num_threads)
      #pragma omp section
        divide_and_conquer(right, total_num_threads)

  else:
    divide_and_conquer(left, total_num_threads)
    divide_and_conquer(right, total_num_threads)

  job = merge(left, right)

Если я вызываю этот код с total_num_threads значением 4, условный аннотированный с помощью (1) всегда будет оцениваться как true (поскольку каждая команда потока будет содержать не более двух потоков), и, следовательно, код всегда будет появляться два новых потока, независимо от того, сколько потоков уже выполняется на более высоком уровне.

Я ищу платформенно-независимый способ определения общего количества потоков, которые в настоящее время работают в моем приложении.

Ответ 1

Имея в виду, что вы знаете точное количество создаваемых потоков, самое простое решение, которое я придумал, - это сохранить свой счетчик потоков.

Знайте, что я полностью в темноте о OpenMP, поскольку я никогда не использовал его.

Ответ 2

Я думаю, что нет такой процедуры, по крайней мере, в OpenMP 3; и если бы это было, я не уверен, что это поможет, так как очевидно, что существует огромное условие гонки между подсчетом числа потоков и разветвления. Вы можете в конечном итоге превысить целевое количество потоков почти в 2 раза, если все видят, что место для одного потока осталось, а затем каждый порождает поток.

Если это действительно структура вашей программы, и вы просто хотите ограничить общее количество потоков, есть опции (все это OpenMP 3.0):

  • Используйте переменную среды OMP_THREAD_LIMIT, чтобы ограничить общее число потоков OpenMP
  • Используйте OMP_MAX_ACTIVE_LEVELS или omp_set_max_active_levels() или выполните проверку на omp_get_level(), чтобы ограничить глубину вложенности ваших потоков; если вы хотите только 16 потоков, ограничьте до 4 уровней вложенности.
  • Если вам нужен более тонкий контроль, чем два, вы можете использовать omp_get_level(), чтобы найти свой уровень, и вызвать omp_get_ancestor_thread_num(int level) на разных уровнях, чтобы узнать, какой поток был вашим родителем, дедушкой и т.д. и из этого (с помощью этого простое левое правое форсирование) определяют глобальный идентификатор потока. (Я думаю, что в этом случае он будет похож на Σ l = 0..L-1 a l 2 Ll где l - уровень число, начинающееся с 0, а - номер порога предка на этом уровне). Это позволит вам (скажем) разрешить потоки 0-3 для вилки, но не 4-7, так что вы получите 12, а не 16 потоков. Я думаю, что это работает только в такой регулярной ситуации; если каждый родительский поток разветкил другое число дочерних потоков, я не думаю, что вы могли бы определить уникальный идентификатор глобального потока, потому что похоже, что вы можете запросить только своих прямых предков.

Ответ 3

В коде, который вы указали, существует проблема, заключающаяся в том, что раздел "omp" должен находиться в лексической области "разделов omp". Я предполагаю, что вы означали, что "omp parallel" означает "параллельные секции omp". Другой способ сделать это - использовать "omp task", а затем вам не нужно учитывать количество потоков. Вы просто назначили потоки параллельной области и разрешили реализации OpenMP назначать задачи для потоков.