В OpenMP, помимо директивы синхронизации BARRIER, имеется набор встроенных подпрограмм и функций для синхронизации нитей с помощью механизма замков. Различают два типа замков - одинарные и множественные. Одинарный замок может быть захвачен одной нитью только один раз, при этом он переходит в состояние заблокированный и может быть разблокирован только этой же нитью. Множественные замки могут захватываться нитью многократно. Для этого вводится понятие коэффициента <захваченности> (nested count), который при каждом захвате увеличивается на 1. Множественный замок считается разблокированным, когда его коэффициент <захваченности> равен 0.
OMP_INIT_LOCK - подпрограмма инициализации замка.
C/C++:
#include <omp.h>
void omp_init_lock(omp_lock_t *lock)
void omp_init_nest_lock(omp_nest_lock_t *lock)
Fortran:
SUBROUTINE OMP_INIT_LOCK(var)
SUBROUTINE OMP_INIT_NEST_LOCK(var)
В языке Фортран переменная var должна быть целого типа, достаточной длины для покрытия всего адресного пространства программы, т.е. на 64-х битных системах следует использовать тип INTEGER*8. Функция создает новый замок, устанавливая его в состояние <разблокированный>. Для множественного замка коэффициент <захваченности> устанавливается в 0.
OMP_DESTROY_LOCK - подпрограмма деинициализации замка.
C/C++:
#include <omp.h>
void omp_destroy_lock(omp_lock_t *lock)
void omp_destroy_nest_lock(omp_nest_lock_t *lock)
Fortran:
SUBROUTINE OMP_DESTROY_LOCK(var)
SUBROUTINE OMP_DESTROY_NEST_LOCK(var)
OMP_SET_LOCK - подпрограмма захвата замка.
C/C++:
#include <omp.h>
void omp_set_lock(omp_lock_t *lock)
void omp_set_nest_lock(omp_nest_lock_t *lock)
Fortran:
SUBROUTINE OMP_SET_LOCK(var)
SUBROUTINE OMP_SET_NEST_LOCK(var)
Нить, вызвавшая эту функцию, дожидается освобождения замка, затем захватывает его. Если множественный замок уже захвачен данной нитью, то нить не блокируется, а увеличивается на единицу коэффициент <захваченности>.
OMP_UNSET_LOCK - подпрограмма освобождения замка.
C/C++:
#include <omp.h>
void omp_unset_lock(omp_lock_t *lock)
void omp_unset_nest_lock(omp_nest_lock_t *lock)
Fortran:
SUBROUTINE OMP_UNSET_LOCK(var)
SUBROUTINE OMP_UNSET_NEST_LOCK(var)
Замок может быть освобожден только захватившей его нитью. Если множественный замок был захвачен данной нитью, то уменьшается на единицу коэффициент <захваченности>.
OMP_TEST_LOCK - неблокирующая функция захвата замка.
C/C++:
#include <omp.h>
void omp_test_lock(omp_lock_t *lock)
void omp_test_nest_lock(omp_nest_lock_t *lock)
Fortran:
LOGICAL FUNCTION OMP_TEST_LOCK(var)
LOGICAL FUNCTION OMP_TEST_NEST_LOCK(var)
Нить, вызвавшая эту функцию, пытается захватить замок, но не блокируется, если это не возможно.
В заключение рассмотрения функций работы с замками приведем пример простой программы на использование этих функций.
Программа lock.c
#include <stdio.h> #include <omp.h> omp_lock_t simple_lock; int main() { omp_init_lock(&simple_lock); #pragma omp parallel num_threads(4) { int tid = omp_get_thread_num(); while (!omp_test_lock(&simple_lock)) printf("Thread %d - failed to acquire simple_lock\n", tid); printf("Thread %d - acquired simple_lock\n", tid); printf("Thread %d - released simple_lock\n", tid); omp_unset_lock(&simple_lock); } omp_destroy_lock(&simple_lock); }
Результат работы:
Thread 2 - acquired simple_lock Thread 2 - released simple_lock Thread 0 - failed to acquire simple_lock Thread 0 - acquired simple_lock Thread 0 - released simple_lock Thread 1 - failed to acquire simple_lock Thread 1 - acquired simple_lock Thread 1 - released simple_lock Thread 3 - failed to acquire simple_lock Thread 3 - acquired simple_lock Thread 3 - released simple_lock
Программа lock.f
program lockf include "omp_lib.h" integer (kind=omp_lock_kind) lock INTEGER tid CALL omp_init_lock(lock) !$OMP PARALLEL NUM_THREADS(4) PRIVATE(tid) tid = omp_get_thread_num() DO WHILE(.NOT. omp_test_lock(lock)) print *, 'Thread =', tid, 'failed to set lock' END DO print *, 'Thread =', tid, 'set lock' CALL omp_unset_lock(lock) print *, 'Thread =', tid, 'released lock' !$OMP END PARALLEL CALL omp_destroy_lock(lock) END
Результат работы:
Thread = 3 set lock Thread = 3 released lock Thread = 0 failed to set lock Thread = 0 set lock Thread = 0 released lock Thread = 1 failed to set lock Thread = 1 set lock Thread = 1 released lock Thread = 2 failed to set lock Thread = 2 set lock Thread = 2 released lock