Книга: Программирование для Linux. Профессиональный подход
4.4.3. Взаимоблокировки исключающих семафоров
4.4.3. Взаимоблокировки исключающих семафоров
Исключающие семафоры являются механизмом, позволяющим одному потоку блокировать выполнение другого потока. Это приводит к возникновению нового класса ошибок. называемых взаимоблокировками или тупиковыми ситуациями. Смысл ошибки в том. что один или несколько потоков ожидают наступления события, которое на самом деле никогда не произойдет.
Простейшая тупиковая ситуация — когда один поток пытается захватить тот же самый исключающий семафор дважды подряд. Дальнейшие действия зависят от типа исключающего семафора. Их всего три.
? Захват быстрого семафора (используется по умолчанию) приведет к взаимоблокировке. Функция, обращающаяся к захваченному семафору данного типа, заблокирует поток до тех пор, пока семафор не будет освобожден. Но семафор принадлежит самому потоку, поэтому блокировка никогда не будет снята.
? Захват рекурсивного семафора не приведет к взаимоблокировке. Семафор данного типа запоминает, сколько раз функция pthread_mutex_lock()
была вызвана в потоке, которому принадлежит семафор. Чтобы освободить семафор и позволить другим потокам обратиться к нему, необходимо аналогичное число раз вызвать функцию pthread_mutex_unlock()
.
? Операционная система Linux обнаруживает попытку повторно захватить контролирующий семафор и сигнализирует об этом: при очередном вызове функции pthread_mutex_lock()
возвращается код ошибки EDEADLK
.
По умолчанию в Linux создается быстрый семафор. В двух других случаях требуется предварительно создать объект атрибутов семафора, объявив переменную типа pthread_mutexattr_t
и передав указатель на нее функции pthread_mutexattr_init()
. Затем нужно задать тип исключающего семафора с помощью функции pthread_mutexattr_setkind_np()
. Первым ее аргументом является указатель на объект атрибутов семафора; второй аргумент равен PTHREAD_MUTEX_RECURSIVE_NP
в случае рекурсивного семафора и PTHREAD_MUTEX_ERRORCHECK_NP
— в случае контролирующего семафора. Указатель на полученный объект атрибутов необходимо передать функции pthread_mutex_init()
, которая создаст семафор. После этого нужно удалить объект атрибутов с помощью функции pthread_mutexattr_destroy()
.
Следующий фрагмент программы иллюстрирует процесс создания контролирующего семафора:
pthread_mutexattr_t attr;
pthread_mutex_t mutex;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
pthread_mutex_init(&mutex, &attr);
pthread_mutexattr_destroy(&attr);
Как подсказывает префикс "np" (not portable), исключающие семафоры рекурсивного и контролирующего типов специфичны для Linux и непереносимы в другие операционные системы. Поэтому не рекомендуется использовать их в программах широкого назначения.
- 4.4.4. Неблокирующие проверки исключающих семафоров
- 4.4.7. Взаимоблокировки двух и более потоков
- Реализация семафоров в Linux
- 10.16. Реализация с использованием семафоров System V
- Синхронизация с помощью семафоров
- 5.2.4. Отладка семафоров
- Взаимоблокировки
- Создание и инициализация семафоров
- Использование семафоров
- Сравнение спин-блокировок и семафоров
- Функции взаимоблокировки
- Мьютексы, критические участки кода и взаимоблокировки