Средства синхронизации потоков управления
Функции, обслуживающие мьютексы, можно разбить на следующие группы:
- инициализация и разрушение мьютексов: pthread_mutex_init(), pthread_mutex_destroy();
- захват и освобождение мьютексов: pthread_mutex_lock(), pthread_mutex_trylock(), pthread_mutex_timedlock(), pthread_mutex_unlock();
- опрос и установка атрибутов мьютекса:
pthread_mutex_getprioceiling(), pthread_mutex_setprioceiling();
- инициализация и разрушение атрибутных объектов мьютексов:
pthread_mutexattr_init(), pthread_mutexattr_destroy();
- опрос и установка атрибутов мьютекса в атрибутных объектах:
pthread_mutexattr_gettype(), pthread_mutexattr_settype(), pthread_mutexattr_getpshared(), pthread_mutexattr_setpshared(), pthread_mutexattr_getprotocol(), pthread_mutexattr_setprotocol(), pthread_mutexattr_getprioceiling(), pthread_mutexattr_setprioceiling();
Для инициализации статически описанных мьютексов с подразумеваемыми значениями атрибутов целесообразно пользоваться макросом PTHREAD_MUTEX_INITIALIZER.
У инициализированного мьютекса имеется четыре атрибута:
- тип (обслуживается функциями pthread_mutexattr_gettype() и pthread_mutexattr_settype());
- верхняя грань приоритетов выполнения (функции pthread_mutex_getprioceiling(), pthread_mutex_setprioceiling(), pthread_mutexattr_getprioceiling(), pthread_mutexattr_setprioceiling());
- протокол (pthread_mutexattr_getprotocol(), pthread_mutexattr_setprotocol());
- признак использования несколькими процессами (pthread_mutexattr_getpshared(), pthread_mutexattr_setpshared()).
В стандарте POSIX-2001 определены четыре типа мьютексов:
PTHREAD_MUTEX_NORMAL, PTHREAD_MUTEX_ERRORCHECK, PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_DEFAULT.
Атрибут "протокол" влияет на планирование потока управления во время владения мьютексом. Согласно стандарту, возможных протоколов три: PTHREAD_PRIO_NONE, PTHREAD_PRIO_INHERIT, PTHREAD_PRIO_PROTECT.
Пусть имеется некоторый предикат (условие), зависящий от значений переменных, разделяемых несколькими потоками управления. Совместное использование мьютексов, переменных условия и обслуживающих их функций позволяет организовать экономное ожидание состояния истинности этого предиката.
С разделяемыми переменными, фигурирующими в предикате, ассоциируется мьютекс, который необходимо захватить перед началом проверок. Затем поток управления входит в цикл вида
while (! предикат) { Ожидание на переменной условия с освобождением мьютекса. После успешного завершения ожидания поток вновь оказывается владельцем мьютекса. }
После нормального выхода из цикла проверяемое условие истинно; можно выполнить требуемые действия и освободить мьютекс.
Разблокирование потоков управления, ожидающих на переменной условия, должен обеспечить другой поток, изменивший значения разделяемых переменных и отправивший ждущим соответствующее уведомление.
Функции, предлагаемые стандартом POSIX-2001 для обслуживания переменных условия, можно разделить на следующие группы:
- инициализация и разрушение переменных условия:
pthread_cond_init(), pthread_cond_destroy(); - блокирование (ожидание) на переменной условия:
pthread_cond_wait(), pthread_cond_timedwait(); - разблокирование (прекращение ожидания) потоков управления, блокированных на переменной условия: pthread_cond_broadcast(), pthread_cond_signal();
- инициализация и разрушение атрибутных объектов переменных условия: pthread_condattr_init(), pthread_condattr_destroy();
- опрос и установки атрибутов переменных условия в атрибутных объектах: признака использования несколькими процессами (обслуживается функциями pthread_condattr_getpshared(), pthread_condattr_setpshared()) и идентификатора часов реального времени, используемых для ограничения ожидания на переменной условия (функции pthread_condattr_getclock(), pthread_condattr_setclock().
Блокировки чтение-запись – интеллектуальное средство синхронизации, отличающее читателей от писателей. В большинстве случаев разделяемые данные чаще читают, чем изменяют, и это делает блокировки чтение-запись весьма употребительными.
Применительно к блокировкам чтение-запись предоставляются следующие группы функций:
- инициализация и разрушение блокировок:
pthread_rwlock_init(), pthread_rwlock_destroy(); - установка блокировки на чтение: pthread_rwlock_rdlock(), pthread_rwlock_tryrdlock(), pthread_rwlock_timedrdlock();
- установка блокировки на запись: pthread_rwlock_wrlock(), pthread_rwlock_trywrlock(), pthread_rwlock_timedwrlock();
- снятие блокировки чтение-запись: pthread_rwlock_unlock();
- инициализация и разрушение атрибутных объектов блокировок:
pthread_rwlockattr_init(), pthread_rwlockattr_destroy(); - опрос и установки атрибутов блокировок в атрибутных объектах:
pthread_rwlockattr_getpshared(), pthread_rwlockattr_setpshared().
Спин- блокировки представляют собой низкоуровневое средство синхронизации, предназначенное в первую очередь для применения в многопроцессорных конфигурациях с разделяемой памятью. По сравнению с мьютексами спин-блокировки могут иметь то преимущество, что (активное) ожидание и установка не связаны с переключением контекстов, активизацией планировщика и т.п. Если ожидание оказывается кратким, минимальными будут и накладные расходы.
Согласно стандарту POSIX-2001, спин-блокировки обслуживаются следующими группами функций:
- инициализация и разрушение спин-блокировок:
pthread_spin_init(), pthread_spin_destroy(); - установка спин-блокировки: pthread_spin_lock(), pthread_spin_trylock();
- снятие спин-блокировки: pthread_spin_unlock().
Барьеры – своеобразное средство синхронизации, идея которого заключается в том, чтобы в определенной точке ожидания собралось заданное число потоков управления. Только после этого они смогут продолжить выполнение.
Барьеры полезны для организации коллективных распределенных вычислений в многопроцессорной конфигурации, когда каждый участник (поток управления) выполняет часть работы, а в точке сбора частичные результаты объединяются в общий итог.
Функции, ассоциированные с барьерами, подразделяются на следующие группы:
- инициализация и разрушение барьеров: pthread_barrier_init(), pthread_barrier_destroy();
- синхронизация на барьере: pthread_barrier_wait();
- инициализация и разрушение атрибутных объектов барьеров:
pthread_barrierattr_init(), pthread_barrierattr_destroy(); - опрос и установки атрибутов барьеров в атрибутных объектах:
pthread_barrierattr_getpshared(), pthread_barrierattr_setpshared(). Когда к функции pthread_barrier_wait() обратилось требуемое число потоков управления, одному из них (стандарт POSIX-2001 не специфицирует, какому именно) в качестве результата возвращается именованная константа PTHREAD_BARRIER_SERIAL_THREAD, а всем другим достаются нули.После этого барьер возвращается в начальное (инициализированное) состояние, а выделенный поток может выполнить соответствующие объединительные действия.