PTHREAD_MUTEXATTR_SETROBUST(3) | Руководство программиста Linux | PTHREAD_MUTEXATTR_SETROBUST(3) |
pthread_mutexattr_getrobust, pthread_mutexattr_setrobust - возвращает и изменяет атрибут устойчивости в объекте мьютексных атрибутов
#include <pthread.h>
int pthread_mutexattr_getrobust(const pthread_mutexattr_t *attr, int *robustness); int pthread_mutexattr_setrobust(const pthread_mutexattr_t *attr, int robustness);
Компилируется и компонуется вместе с -pthread.
Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):
pthread_mutexattr_getrobust(), pthread_mutexattr_setrobust():
Функция pthread_mutexattr_getrobust() помещает значение атрибута устойчивости (robustness) из объекта мьютексных атрибутов, на который указывает attr, в *robustness. Функция pthread_mutexattr_setrobust() изменяет значение атрибута устойчивости в объекте мьютексных атрибутов, на который указывает attr, на значение, заданное в *robustness.
Атрибут устойчивости определяет поведение мьютекса после того как владеющая нить завершает работу, но не разблокировала мьютекс. Для robustness возможны следующие значения:
Заметим, что аргумент attr у pthread_mutexattr_getrobust() и pthread_mutexattr_setrobust() должен указывать на объект мьютексных атрибутов, который был инициализирован pthread_mutexattr_init(3), в противном случае поведение не определено.
При успешном выполнении эти функции возвращают 0. При ошибке возвращается положительный номер ошибки.
В реализации glibc функция pthread_mutexattr_getrobust() всегда возвращает ноль.
Функции pthread_mutexattr_getrobust() и pthread_mutexattr_setrobust() добавлены в glibc версии 2.12.
POSIX.1-2008.
В реализации Linux при использовании общих для процессов устойчивых мьютексов ожидающая нить также получает уведомление EOWNERDEAD, если владелец устойчивого мьютекса выполняет execve(2) без предварительной разблокировки мьютекса. В POSIX.1 не указана данная подробность, но такое же поведение также встречается и в нескольких других реализациях.
До появления pthread_mutexattr_getrobust() и pthread_mutexattr_setrobust() в POSIX, в glibc определись следующие эквиваленты нестандартных функций, если определён _GNU_SOURCE:
int pthread_mutexattr_getrobust_np(const pthread_mutexattr_t *attr, int *robustness); int pthread_mutexattr_setrobust_np(const pthread_mutexattr_t *attr, int robustness);
Соответственно, также определены константы PTHREAD_MUTEX_STALLED_NP и PTHREAD_MUTEX_ROBUST_NP.
Данный имеющийся только в GNU программный интерфейс, впервые появившийся в glibc 2.4, в настоящее время устарел и не должен использоваться в новых программах.
В программе, представленной далее, показывается использование атрибута устойчивости в объекте мьютексных атрибутов. В этой программе нить, удерживающая мьютекс, завершает работу без разблокировки мьютекса. После этого главная нить захватывает мьютекс и получает ошибку EOWNERDEAD, после чего делает мьютекс согласованным.
Пример сеанса работы с программой:
$ ./a.out [первый владелец] Установка блокировки… [первый владелец] Готово. Теперь выходим без разблокировки. [главная нить] Пытаемся получить заблокировать устойчивый мьютекс. [главная нить] pthread_mutex_lock() вернула EOWNERDEAD [главная нить] Теперь делаем мьютекс согласованным [главная нить] Мьютекс согласован; разблокируем
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <pthread.h> #include <errno.h> #define handle_error_en(en, msg) \ do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0) static pthread_mutex_t mtx; static void * original_owner_thread(void *ptr) { printf("[первый владелец] Установка блокировки…\n"); pthread_mutex_lock(&mtx); printf("[original owner] Готово. Теперь выходим без разблокировки.\n"); pthread_exit(NULL); } int main(int argc, char *argv[]) { pthread_t thr; pthread_mutexattr_t attr; int s; pthread_mutexattr_init(&attr); /* инициализируем объект атрибутов */ pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST); /* задаём устойчивость */ pthread_mutex_init(&mtx, &attr); /* инициализируем мьютекс */ pthread_create(&thr, NULL, original_owner_thread, NULL); sleep(2); /* «нить_первый_владелец» к этому моменту должна завершиться */ printf("[главная нить] Пытаемся получить заблокировать устойчивый мьютекс.\n"); s = pthread_mutex_lock(&mtx); if (s == EOWNERDEAD) { printf("[главная нить] pthread_mutex_lock() вернула EOWNERDEAD\n"); printf("[главная нить] Теперь делаем мьютекс согласованным\n"); s = pthread_mutex_consistent(&mtx); if (s != 0) handle_error_en(s, "pthread_mutex_consistent"); printf("[главная нить] Мьютекс согласован; разблокируем\n"); s = pthread_mutex_unlock(&mtx); if (s != 0) handle_error_en(s, "pthread_mutex_unlock"); exit(EXIT_SUCCESS); } else if (s == 0) { printf("[главная нить] pthread_mutex_lock() неожиданно завершилась успешно\n"); exit(EXIT_FAILURE); } else { printf("[главная нить] pthread_mutex_lock() завершилась с ошибкой\n"); handle_error_en(s, "pthread_mutex_lock"); } }
get_robust_list(2), set_robust_list(2), pthread_mutex_init(3), pthread_mutex_consistent(3), pthread_mutex_lock(3), pthreads(7)
2019-03-06 | Linux |