Освобождение параметров
int pthread_mutexattr_destroy(pthread_mutexattr_t* attr);
Вызов разрушает ранее применявшийся объект - атрибутную запись мьютекса, после чего она уже не может более использоваться для инициализации мьютекса без предварительного выполнения вызова pthread_mutexattr_init()
.
На этом обсуждение атрибутов заканчивается, и мы переходим непосредственно к функциям работы с мьютексом.
Операции над мьютексом
Инициализация мьютекса
int pthread_mutex_init(pthread_mutex_t* mutex,
const pthread_mutexattr_t* attr);
Структура данных pthread_mutex_t
определена в файле <pthread.h>
(производный тип от типа sync_t
, который в свою очередь определен в файле <target_nto.h>
) и имеет следующий вид:
struct _sync_t {
/* Счетчик для рекурсивного мьютекса или семафора */
int count;
/* TID потока - имеет смысл и применяется только для мьютексов */
unsigned owner;
};
Функция pthread_mutex_init()
инициализирует переданный объект мьютекс в соответствии со значением переданных атрибутов. Если вместо attr
передать NULL
, то мьютекс будет создан в соответствии со значениями атрибутов по умолчанию. В native QNX API эта функция реализуется вызовом SyncTypeCreate()
. SyncTypeCreate ()
— единая функция для создания всех базовых объектов синхронизации QNX Neutrino.
Вместо прямого вызова функции pthread_mutex_init()
для начальной инициализации статических мьютексов (глобальных на уровне файла кода или пространства имен namespace либо явно описанных с квалификатором static) можно воспользоваться двумя макросами PTHREAD_MUTEX_INITIALIZER
и PTHREAD_RMUTEX_INITIALIZER
:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_RMUTEX_INITIALIZER;
Первый из них создает мьютекс в соответствии со значениями атрибутов по умолчанию, а второй - мьютекс с разрешенным рекурсивным захватом.
Операции с граничным приоритетом
Большинство параметров мьютекса не могут быть изменены после его создания. Но не все. В процессе работы с мьютексом может быть изменено значение приоритета, которое система использует для реализации протокола граничного приоритета с целью предотвращения инверсии приоритетов:
int pthread_mutex_setprioceiling(pthread_mutex_t* mutex,
int prioceiling, int* old_ceiling);
int pthread_mutex_getprioceiling(const pthread_mutex_t* mutex,
int* prioceiling);
Функция pthread_mutex_setprioceiling()
захватывает мьютекс (или блокируется, пока мьютекс не будет освобожден, и уже тогда захватывает его) и изменяет установленную для него величину граничного приоритета, после чего освобождает мьютекс для использования другими потоками. После изменения значения граничного приоритета предыдущее значение возвращается в old_ceiling
.
Функция возвращает следующие значения:
EOK
— успешное завершение;
EINVAL
— указанный в вызове мьютекс не существует или указанный приоритет выходит за диапазон допустимых значений;
EPERM
— поток, вызвавший функцию, не имеет прав на изменение граничного приоритета указанного мьютекса.
Захват мьютекса
Захват мьютекса может производиться тремя разными функциями, в основе которых лежит функция из 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
— успешное завершение;