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