Чтение онлайн

ЖАНРЫ

QNX/UNIX: Анатомия параллелизма
Шрифт:

Функция

pthread_mutex_lock
может возвращать следующие значения: EOK — успешное завершение;

EAGAIN
— недостаточно системных ресурсов для захвата мьютекса;

EDEADLK
— вызывающий поток уже владеет мьютексом и мьютекс не поддерживает рекурсивный захват (режим контроля ошибок);

EINVAL
— некорректное значение параметра
mutex
.

Попытка захвата

int pthread_mutex_trylock(pthread_mutex_t* mutex);

Функция проверяет, свободен ли мьютекс

mutex
, и если да, то она захватывает его. В противном
случае функция возвращает значение
EBUSY
.

Возвращаемые значения:

EOK
— успешное завершение;

EAGAIN
— недостаточно системных ресурсов для захвата мьютекса;

EBUSY
— мьютекс
mutex
уже захвачен;

EINVAL
— некорректное значение параметра
mutex.

Захват с установкой времени ожидания

#include <pthread.h>

#include <time.h>

int pthread_mutex_timedlock(pthread_mutex_t* mutex,

const struct timespec* abs_timeout);

Функция проверяет, свободен ли мьютекс (

mutex
), и если да, то поток, в котором вызвана функция, захватывает этот мьютекс. Если мьютекс уже захвачен, вызвавший поток блокируется до освобождения мьютекса либо до наступления времени, указанного в аргументе
abs_timeout
. Если это время уже наступило, поток не блокируется вообще, но захват все-таки произойдет, если мьютекс свободен.

Наступление времени определяется по часам

REALTIME_CLOCK
, когда значение часов оказывается равным или большим значения, указанного в
abs_timeout
. Тип данных timespec определен в файле
<time.h>
.

Если мьютекс создан с атрибутом протокола

PRIO_INHERIT
, то после выхода потока из блокировки на мьютексе по тайм-ауту приоритет владельца мьютекса подвергается пересмотру в соответствии с приоритетами потоков, оставшихся в очереди на захват мьютекса.

Возвращаемые значения:

EOK
— успешное завершение;

EAGAIN
недостаточно системных ресурсов для захвата мьютекса;

EDEADLK
— вызывающий поток уже владеет мьютексом, который не поддерживает рекурсивный захват (режим контроля ошибок);

EINVAL
— мьютекс использует протокол граничного приоритета для предотвращения инверсии (атрибут
protocol
установлен в значение
PTHREAD_PRIO_PROTECT
), но приоритет вызвавшего потока выше граничного приоритета, присвоенного мьютексу; поток должен быть блокирован (мьютекс не свободен), а значение поля
abs_timeout
, показывающее количество наносекунд, меньше нуля или больше 1000 миллионов; переменная, на которую указывает
mutex
, не является инициированным объектом — мьютексом.

ETIMEDOUT
— мьютекс не может быть захвачен, поскольку указанный тайм-аут истек.

Освобождение мьютекса

int pthread_mutex_unlock(pthread_mutex_t* mutex);

Функция

pthread_mutex_unlock
освобождает мьютекс, на который ссылается переменная
mutex
. Вызвавший поток должен быть владельцем мьютекса. Если есть потоки, блокированные в ожидании освобождения мьютекса, то поток с наивысшим приоритетом (или при равных приоритетах дольше всех ждавший) выходит из блокированного состояния и становится владельцем мьютекса.

Для мьютексов,

разрешающих рекурсивный захват, функция освобождения должна вызываться столько же раз, сколько и функция захвата.

Возвращаемые значения:

EOK
— успешное завершение;

EINVAL
— переменная, на которую указывает
mutex
, не является инициализированным объектом — мьютексом;

EPERM
— вызвавший поток не является владельцем мьютекса.

Разрушение объекта мьютекс

int pthread_mutex_destroy(pthread_mutex_t* mutex);

Вызов разрушает объект мьютекс, на который указывает переменная

mutex
. После чего эта переменная не может быть использована без предварительного вызова
pthread_mutex_init
.

Возвращаемые значения:

EOK
— успешное завершение;

EBUSY
мьютекс захвачен и не может быть разрушен до освобождения;

EINVAL
— переменная, на которую указывает
mutex
, не является инициированным объектом - мьютексом.

Операции, не поддерживаемые POSIX

В native QNX API есть ряд функций работы с мьютексом, которые не определены POSIX-стандартом, однако они могут оказаться весьма полезными. Поскольку тип POSIX-мьютекса порождается от

sync_t
, то вполне возможно использование комбинации функций, определенных POSIX, и «родных» native-функций QNX. Однако необходимо помнить, что в таком случае ни о какой межсистемной совместимости говорить уже не приходится.

Восстановление «мертвого» мьютекса

#include <sys/neutrino.h>

int SyncMutexRevive(sync_t* sync);

int SyncMutexRevive_r(sync_t* sync);

Эти функции [36] предназначены для восстановления мьютекса, который находится в состоянии блокирования

DEAD
. Мьютекс попадает в состояние
DEAD
, когда память, использованная при захвате мьютекса, освобождается. Такое может произойти, например, когда умирает поток, захвативший мьютекс, расположенный в разделяемой памяти. В результате вызова вызвавший поток становится владельцем мьютекса, и его счетчик захватов устанавливается в 1 для рекурсивного мьютекса.

36

Функции

SyncMutexRevive
и
SyncMutexRevive_r
, из которых вторая является потокобезопасной формой первой, как это описывалось выше, отличаются между собой только способом уведомления об ошибке: первая форма возвращает -1 в случае ошибки и устанавливает
errno
, а вторая непосредственно возвращает код ошибки.

Ошибки выполнения функции:

ЕFAULT
— ошибка при обращении к указанным в аргументах переменным;

EINVAL
— указанный объект синхронизации не существует или не находится в состоянии
DEAD
;

ETIMEDOUT
— отмена вызова по тайм-ауту ядра (устанавливается вызовом
TimerTimeout
).

Установка уведомления о «смерти» мьютекса

Определить состояние мьютекса как

DEAD
можно с помощью функции
SyncMutexEvent
, которая определяет событие, связанное со «смертью» мьютекса.

Поделиться с друзьями: