Мобильное программирование приложений реального времени в стандарте POSIX

       

Спин-блокировки


Спин-блокировки представляют собой чрезвычайно низкоуровневое средство синхронизации, предназначенное в первую очередь для применения в многопроцессорной конфигурации с разделяемой памятью. Они обычно реализуются как атомарно устанавливаемое булево значение (истина – блокировка установлена). Аппаратура поддерживает подобные блокировки командами вида "проверить и установить".

При попытке установить спин-блокировку, если она захвачена кем-то другим, как правило, применяется активное ожидание освобождения, с постоянным опросом в цикле состояния блокировки. Естественно, при этом занимается процессор, так что спин-блокировки следует устанавливать только на очень короткое время и их владелец не должен приостанавливать свое выполнение.

Для описываемых блокировок стандарт 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)

Спин-блокировка устанавливается на очень короткий участок кода; естественно, она должна быть реализована весьма эффективно, чтобы накладные расходы не оказались чрезмерными.


Содержание раздела