Изменить стиль страницы

Захват мьютекса

Захват мьютекса может производиться тремя разными функциями, в основе которых лежит функция из native QNX API

SyncMutexLock()
.

Простой захват

int pthread_mutex_lock(pthread_mutex_t* mutex);

Функция захватывает мьютекс, на который ссылается

mutex
. Если мьютекс уже захвачен другим потоком, то вызвавший поток блокируется до освобождения мьютекса и после этого захватывает его. Только после этого функция
pthread_mutex_lock()
возвращает управление. Если захватить мьютекс пытается поток, который им уже владеет, то поведение функции
pthread_mutex_lock()
будет зависеть от значений атрибутов мьютекса, указанных при его создании. QNX предоставляет возможность рекурсивного захвата мьютекса при соответствующих настройках атрибутов (см. выше раздел «Параметры мьютекса»). При создании мьютекса с параметрами по умолчанию попытка повторного захвата мьютекса ни к чему не приводит. Если включен режим контроля ошибок и отключен рекурсивный захват мьютекса, функция
pthread_mutex_lock()
возвращает
EDEADLK
при попытке повторного захвата мьютекса тем же потоком.

Функция

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. Однако необходимо помнить, что в таком случае ни о какой межсистемной совместимости говорить уже не приходится.