Спин-блокировки
Спин-блокировки представляют собой чрезвычайно низкоуровневое средство синхронизации, предназначенное в первую очередь для применения в многопроцессорной конфигурации с разделяемой памятью. Они обычно реализуются как атомарно устанавливаемое булево значение (истина – блокировка установлена). Аппаратура поддерживает подобные блокировки командами вида "проверить и установить".
При попытке установить спин-блокировку, если она захвачена кем-то другим, как правило, применяется активное ожидание освобождения, с постоянным опросом в цикле состояния блокировки. Естественно, при этом занимается процессор, так что спин-блокировки следует устанавливать только на очень короткое время и их владелец не должен приостанавливать свое выполнение.
Для описываемых блокировок стандарт POSIX-2001 не предусматривает установки с ограниченным ожиданием. Это понятно, поскольку накладные расходы по времени на ограничение в типичном случае превысят само время ожидания.
По сравнению с мьютексами спин-блокировки могут иметь то преимущество, что (активное) ожидание и установка не связаны с переключением контекстов, активизацией планировщика и т.п. Если ожидание оказывается кратким, минимальными оказываются и накладные расходы. Приложение, чувствительное к подобным тонкостям, в каждой конкретной ситуации может выбрать наиболее эффективное средство синхронизации.
Согласно стандарту POSIX-2001, спин-блокировки обслуживаются следующими группами функций:
- инициализация и разрушение спин-блокировок: pthread_spin_init(), pthread_spin_destroy() (см. листинг 2.32);
#include <pthread.h>
int pthread_spin_init ( pthread_spinlock_t *lock, int pshared);
int pthread_spin_destroy ( pthread_spinlock_t *lock);
Листинг 2.32. Описание функций инициализации и разрушения спин-блокировок. (html, txt)
- установка спин-блокировки: pthread_spin_lock(), pthread_spin_trylock() (см. листинг 2.33);
#include <pthread.h>
int pthread_spin_lock ( pthread_spinlock_t *lock);
int pthread_spin_trylock ( pthread_spinlock_t *lock);
Листинг 2.33. Описание функций установки спин-блокировки. (html, txt)
- снятие спин-блокировки: pthread_spin_unlock() (см. листинг 2.34).
#include <pthread.h> int pthread_spin_unlock ( pthread_spinlock_t *lock);
Листинг 2.34. Описание функции снятия спин-блокировки. (html, txt)
Обратим внимание на то, что применительно к спин-блокировкам было решено не возиться с атрибутными объектами, а единственный поддерживаемый атрибут – признак использования несколькими процессами – задавать при вызове функции pthread_spin_init().
Поскольку между применением мьютексов и спин-блокировок много общего, мы не будем приводить примеры программ, использующих спин-блокировки. Ограничимся маленьким, слегка модифицированным характерным фрагментом реализации функции sigsuspend() в библиотеке glibc (см. листинг 2.35).
pthread_spin_lock (&ss->lock); /* Восстановим старую маску */ ss->blocked = oldmask; /* Проверим ждущие сигналы */ pending = ss->pending & ~ss->blocked; pthread_spin_unlock (&ss->lock);
Листинг 2.35. Фрагмент возможной реализации функции sigsuspend(). (html, txt)
Спин-блокировка устанавливается на очень короткий участок кода; естественно, она должна быть реализована весьма эффективно, чтобы накладные расходы не оказались чрезмерными.