Это функции захвата и попытки захвата крутящейся блокировки соответственно. Как и для мьютекса, если объект
spinner
в момент захвата свободен, то поток, вызвавший одну из этих функций, становится владельцем крутящейся блокировки. Если
spinner
уже захвачен другим потоком, то в случае вызова второй из рассматриваемых функций управление возвращается немедленно, а в случае простого захвата (первая функция) вызвавший поток «крутится», то есть остается активным, но не возвращает управления до тех пор, пока объект синхронизации не освободится.
Попытка повторного захвата крутящейся блокировки из того же потока приводит к мертвой блокировке.
Функции возвращают следующие параметры:
EOK
— успешное выполнение;
EAGAIN
— недостаточно ресурсов системы для захвата
spinner
;
EDEADLK
— вызвавший поток уже владеет
spinner
;
EINVAL
—
spinner
— неверный объект типа
pthread_spinlock_t
;
EBUSY
— объект захвачен другим потоком (для
pthread_spin_trylock
).
int pthread_spin_unlock(pthread_spinlock_t* spinner);
Вызов этой функции освобождает объект крутящейся блокировки, на который указывает аргумент
spinner
.
Функция может возвращать значения:
EOK
— успешное выполнение;
EINVAL
— неверный объект
spinner
;
EPERM
— вызывающий поток не является владельцем крутящейся блокировки.
5. Специфические механизмы QNX
Операционная система QNX изнутри вся построена на клиент-серверных принципах, которые вытекают из микроядерной архитектуры и обмена сообщениями микроядра. Мы не могли обойти вниманием эти механизмы, поскольку они предоставляют огромный арсенал возможностей, однако их обстоятельное описание потребовало бы отдельной книги (полное описание см. в технической документации QNX по системной архитектуре). Более того, лучшая книга по обмену сообщениями микроядра уже, пожалуй, написана и переведена на русский язык [1]. В дополнение ко всему приложение «Организация обмена сообщениями», написанное В. Зайцевым и ранее не публиковавшееся, содержит обстоятельный анализ этого механизма.
Поэтому в главе мы лишь кратко рассмотрим вопросы параллелизма и синхронизации, присущие самой микроядерной архитектуре системы.
Обмен сообщениями микроядра
Модель обмена сообщениями — это тот фундамент, на котором стоит архитектура любой микроядерной ОС, как на трех китах: SEND — RECEIVE — REPLY. Обмен сообщениями микроядра построен на трех группах вызовов native API QNX (рис. 5.1):
1.
Принять сообщение. Процесс
[38], являющийся сервером некоторой услуги, выполняет вызов группы
MsgReceive*
[39], фактически сообщая этим о готовности обслуживать запрос клиента, и переходит при этом в блокированное состояние со статусом RECEIVE, ожидая прихода клиентского запроса.
2.
Послать сообщение. Клиентский процесс запрашивает эту услугу, посылая сообщение вызовом
MsgSend*
, и переходит в блокированное состояние со статусом SEND. Переход осуществляется обычно на очень короткое время, пока сервер не примет его сообщение и не начнет обработку. Как только сервер принимает посланное сообщение, он разблокируется и меняет статус с RECEIVE на READY. Сервер начинает обработку полученного сообщения, а статус блокировки клиентского процесса меняется на REPLY.
3.
Ответить на полученное сообщение. Завершив обработку полученного на предыдущем шаге сообщения, сервер выполняет вызов группы
MsgReply*
для передачи запрошенного результата ожидающему клиенту. После этого вызова клиент, блокированный на вызове
MsgSend*
со статусом REPLY, разблокируется (переходит в состояние READY). После выполнения
MsgReply*
сервер также переходит в состояние READY. Однако чаще всего сервер снова входит в блокированное состояние на вызове
MsgReceive*
, поскольку его работа организована как бесконечный цикл.
Рис. 5.1. Обмен сообщениями микроядра и менеджер ресурсов
Уже из этого поверхностного описания понятно, что передача сообщений микроядра — это не только средство взаимодействия процессов с обменом данными, но и крайне гибкая система синхронизации всех участников взаимодействия.
Могут возникнуть вопросы: Это один из низкоуровневых механизмов (существуют ли другие нативные механизмы?), на которых базируется ОС QNX? Какое это может иметь отношение к взаимодействиям на уровне POSIX API? Самое прямое! Все традиционные вызовы POSIX (
open
,
read
, … и все другие) реализованы в ОС QNX как обмен сообщениями, который только «камуфлируется» под стандарты техникой использования менеджеров ресурсов, о которых разговор еще впереди.
Технология обмена сообщениями микроядра хорошо описана [1] и требует для своего понимания и освоения тщательного изучения. В этой же главе, посвященной совершенно другим предметам, мы не будем детально описывать эту технологию.