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
int SyncMutexRevive(sync_t* sync);
int SyncMutexRevive_r(sync_t* sync);
Эти функции
[36]предназначены для восстановления мьютекса, который находится в состоянии блокирования
DEAD
. Мьютекс попадает в состояние
DEAD
, когда память, использованная при захвате мьютекса, освобождается. Такое может произойти, например, когда умирает поток, захвативший мьютекс, расположенный в разделяемой памяти. В результате вызова вызвавший поток становится владельцем мьютекса, и его счетчик захватов устанавливается в 1 для рекурсивного мьютекса.
Ошибки выполнения функции:
ЕFAULT
— ошибка при обращении к указанным в аргументах переменным;
EINVAL
— указанный объект синхронизации не существует или не находится в состоянии
DEAD
;
ETIMEDOUT
— отмена вызова по тайм-ауту ядра (устанавливается вызовом
TimerTimeout
).
Определить состояние мьютекса как
DEAD
можно с помощью функции
SyncMutexEvent
, которая определяет событие, связанное со «смертью» мьютекса.
#include
int SyncMutexEvent(sync_t* sync, struct sigevent* event);
int SyncMutexEvent_r(sync_t* sync, struct sigevent* event);
Данная функция предназначена для установки обработчика ситуации, когда мьютекс попадает в состояние
DEAD
(то есть перераспределяется память, из которой произошел захват мьютекса). Захватить мьютекс, оказавшийся в состоянии
DEAD
, можно далее с помощью вызова функции
SyncMutexRevive
.
Ошибки выполнения функции:
EAGAIN
— в данный момент ядро не имеет ресурсов для обработки запроса;
EFAULT
— ошибка произошла при попытке обращения к
sync
;
EINVAL
— объект синхронизации, на который указывает
sync
, не существует.
Пример применения мьютекса
Модернизируем наш пример из раздела, посвященного использованию семафора для случая множества потоков источников и приемников данных. Проблема заключается в том, что когда несколько потоков одновременно попытаются вызвать функцию
push
или
pop
, может произойти сильная путаница, поэтому код этих функций должен исполняться эксклюзивно, только одним потоком. Решить эту проблему можно двумя способами: воспользоваться бинарным семафором или мьютексом. Мы решили применить именно мьютекс и ниже расскажем причину, по которой мы здесь смешали в одной конструкции эти два элемента синхронизации.
/* Шаблонный класс очереди данных */
template
public:
CDataQueue { pthread_mutex_init(&_mutex, NULL); }
~CDataQueue { pthread_mutex_destroy(&_mutex); }
void push(T _new_data) {
pthread_mutex_lock(&_mutex);
data_queue.push(_new_data);
data_event.reset;
pthread_mutex_unlock(&_mutex);
}
T pop {
data_event.wait;
pthread_mutex_lock(&_mutex);
T res = data_queue.front;
data_queue.pop;
pthread_mutex_unlock(&_mutex);
return res;
}
private:
std::queue
event data_event;
pthread_mutex_t _mutex;
};