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():

_POSIX_C_SOURCE >= 200809L

ОПИСАНИЕ

Функция pthread_mutexattr_getrobust() помещает значение атрибута устойчивости (robustness) из объекта мьютексных атрибутов, на который указывает attr, в *robustness. Функция pthread_mutexattr_setrobust() изменяет значение атрибута устойчивости в объекте мьютексных атрибутов, на который указывает attr, на значение, заданное в *robustness.

Атрибут устойчивости определяет поведение мьютекса после того как владеющая нить завершает работу, но не разблокировала мьютекс. Для robustness возможны следующие значения:

Значение по умолчанию для объекта мьютексных атрибутов. Если мьютекс инициализирован с атрибутом PTHREAD_MUTEX_STALLED и его владелец завершает работу без его разблокировки, то после этого мьютекс остаётся заблокированным и все последующие попытки вызова pthread_mutex_lock(3) для этого мьютекса будут заблокированы навсегда.
Если мьютекса инициализирован с атрибутом PTHREAD_MUTEX_ROBUST и и его владелец завершает работу без его разблокировки,то все последующие попытки вызова pthread_mutex_lock(3) для этого мьютекса будут успешно выполнены возвращается EOWNERDEAD, чтобы показать, что первоначальный владелец не существует и мьютекс находится в неопределенном состоянии. Обычно, после возврата EOWNERDEAD перед началом использования следующий владелец должен вызвать pthread_mutex_consistent(3) над полученным мьютексом, чтобы снова сделать его согласованным.
Если следующий владелец разблокирует мьютекс с помощью pthread_mutex_unlock(3) до того, как сделать его согласованным, мьютекс станет необратимо неработоспособен и последующие попытки заблокировать его с помощью pthread_mutex_lock(3) будут завершаться ошибкой ENOTRECOVERABLE. Для такого мьютекса доступна только одна операция — pthread_mutex_destroy(3).
Если следующий владелец завершит работу до вызова pthread_mutex_consistent(3), то последующие операций pthread_mutex_lock(3) с этим мьютексом будут по прежнему возвращать EOWNERDEAD.

Заметим, что аргумент attr у pthread_mutexattr_getrobust() и pthread_mutexattr_setrobust() должен указывать на объект мьютексных атрибутов, который был инициализирован pthread_mutexattr_init(3), в противном случае поведение не определено.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении эти функции возвращают 0. При ошибке возвращается положительный номер ошибки.

В реализации glibc функция pthread_mutexattr_getrobust() всегда возвращает ноль.

ОШИБКИ

Помимо PTHREAD_MUTEX_STALLED или PTHREAD_MUTEX_ROBUST в pthread_mutexattr_setrobust() передано что-то ещё.

ВЕРСИИ

Функции 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