Паралельні нотатки N4 – продовжуємо знайомитися з конструкціями OpenMP

Продовжимо знайомство з технологією OpenMP та розглянемо деякі функції та нові директиви.

У OpenMP існує низка допоміжних функцій. Для їх використання не забудьте підключити заголовний файл.

Функції виконуючого середовища

Ці функції дозволяють запитувати та задавати різні параметри середовища OpenMP:

Якщо ім'я функції починається з omp_set_, її можна викликати лише поза паралельними регіонів. Всі інші функції можна використовувати як всередині паралельних регіонів, так і поза ними.

Функції синхронізації/блокування

OpenMP дозволяє будувати паралельний код без використання цих функцій, оскільки є директиви, що дозволяють здійснювати певні види синхронізації. Однак у ряді випадків ці функції зручні та навіть необхідні.

У OpenMP два типи блокувань: прості та вкладені. Вкладені мають суфікс "nest". Блокування можуть бути в одному з трьох станів - неініціалізованому, заблокованому та розблокованому.

  • omp_init_lock/omp_init_nest_lock – ініціалізація змінної типу omp_lock_t/omp_nest_lock_t. Аналог InitializeCriticalSection.
  • omp_destroy_lock/omp_destroy_nest_lock - звільнення змінної типу omp_lock_t/omp_nest_lock_t. Аналог DeleteCriticalSection.
  • omp_set_lock/omp_set_nest_lock - один потік виставляє блокування, інші потоки чекають, поки потік, що викликала цю функцію, не зніме блокування з допомогою функції omp_unset_lock(). Аналог EnterCriticalSection.
  • omp_unset_lock/omp_unset_nest_lock – зняття блокування. Аналог LeaveCriticalSection.
  • omp_test_lock/omp_test_nest_lock – неблокуюча спроба захоплення замка. Ця функція намагається захопити зазначений замок. Якщо це вдалося, то для простого замку функція 1 повертає.Замок захопити не вдалося, то повертається 0. Аналог TryEnterCriticalSection.

Прості блокування (omp_lock_t) не можуть бути встановлені більше одного разу, навіть тим самим потоком. Блокування, що вкладаються (omp_nest_lock_t) ідентичні простим з тим винятком, що коли потік намагається встановити вже належне йому вкладається блокування, він не блокується.

Наведемо приклад коду, який використовує описані функції. Всі потоки по черзі виведуть повідомлення "Begin work" і "End work". Між цими двома повідомленнями від одного потоку можуть зустрітися повідомлення з інших потоків, що виводяться при невдалій спробі увійти до закритої секції.

На машині з чотирма ядрами може бути отриманий такий висновок: