Чтение онлайн

на главную - закладки

Жанры

Программирование для Linux. Профессиональный подход

Самьюэл Алекс

Шрифт:

void enqueue_job(struct job* new_job) {

 pthread_mutex_lock(&job_queue_mutex);

 new_job->next = job_queue;

 job_queue = new_job;

 pthread_mutex_unlock(&job_queue_mutex);

}

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. Неблокирующие проверки исключающих семафоров

Иногда нужно, не заблокировав программу, проверить, захвачен ли исключающий семафор. Для потока не всегда приемлемо находиться в режиме пассивного ожидания, ведь за это время можно сделать много полезного! Функция

pthread_mutex_lock
не возвращает значения до тех пор, пока семафор не будет освобожден, поэтому она нам не подходит.

То, что нам нужно, — это функция

pthread_mutex_trylock
. Если она обнаруживает, что семафор свободен, то захватывает его так же, как и функция
pthread_mutex_lock
, возвращая при этом 0. Если же оказывается, что семафор уже захвачен другим потоком, функция
pthread_mutex_trylock
не блокирует программу, а немедленно завершается, возвращая код ошибки
EBUSY
. "Права собственности" другого потока при этом не нарушаются. Можно попытаться захватить семафор позднее.

4.4.5. Обычные потоковые семафоры

В предыдущем примере, в котором группа потоков обрабатывает задания из очереди, потоковая функция запрашивает задания до тех пор, пока очередь не опустеет, после чего поток завершается. Эта схема работает в том случае, когда все задания помещаются в очередь заранее или новые задания поступают по крайней мере так же часто, как их запрашивают потоки. Но если потоки начнут работать слишком быстро, очередь опустеет и потоки завершатся. Может оказаться, что задание поступило, а потоков, готовых его обработать, уже нет. Следовательно, необходим механизм, который позволит блокировать потоки в случае, когда очередь пуста, а новые задания еще не поступили.

Такой механизм называется семафором. Семафор — это счетчик, используемый для синхронизации потоков. Операционная система гарантирует, что проверка и модификация значения семафора могут быть выполнены безопасно и не приведут к возникновению гонки.

Счетчик семафора является неотрицательным целым числом. Семафор поддерживает две базовые операции.

■ Операция ожидания (wait) уменьшает значение счетчика на единицу. Если счетчик уже равен нулю, операция блокируется до тех пор, пока значение счетчика не станет положительным (вследствие действий, выполняемых другими потоками). После снятия блокировки значение семафора уменьшается на единицу и операция завершается.

■ Операция установки (post) увеличивает значение счетчика на единицу. Если до этого счетчик был равен нулю и существовали потоки, заблокированные в операции ожидания данного семафора, один из них разблокируется и завершает свою операцию (т.е. счетчик семафора снова становится равным нулю).

В Linux имеются две немного отличающиеся реализации семафоров. Та, которую мы опишем ниже, соответствует стандарту POSIX. Такие семафоры применяются для организации взаимодействия потоков. Другая реализация, служащая целям межпроцессного взаимодействия, рассмотрена в разделе 5.2, "Семафоры для процессов". При работе с семафорами необходимо включить в программу файл

<semaphore.h>
.

Семафор представляется переменной типа

sem_t
. Семафор следует предварительно инициализировать с помощью функции
sem_init
, передав ей указатель на переменную семафора. Второй параметр этой функции должен быть равен нулю, [14] а третий — это начальное значение счетчика семафора.

Чтобы выполнить операцию ожидания семафора, необходимо вызвать функцию

sem_wait
. Функция
sem_post
устанавливает семафор. Есть также функция
sem_trywait
, реализующая операцию неблокирующего ожидания. Она напоминает функцию
pthread_mutex_trylock
: если операция ожидания приведет к блокированию потока из-за того, что счетчик семафора равен нулю, функция немедленно завершается, возвращая код ошибки
EAGAIN
.

14

Ненулевое значение определяет семафор, совместно используемый несколькими процессами, но в Linux такой вариант семафоров не поддерживается (семафоры процессов создаются по-другому, а в данном случае речь идет о потоковых семафорах).

Поделиться:
Популярные книги

Инквизитор Тьмы

Шмаков Алексей Семенович
1. Инквизитор Тьмы
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Инквизитор Тьмы

Дважды одаренный. Том IV

Тарс Элиан
4. Дважды одаренный
Фантастика:
городское фэнтези
альтернативная история
аниме
7.00
рейтинг книги
Дважды одаренный. Том IV

Хозяин оков VI

Матисов Павел
6. Хозяин Оков
Фантастика:
фэнтези
попаданцы
гаремник
5.00
рейтинг книги
Хозяин оков VI

Цикл романов "Целитель". Компиляция. Книги 1-17

Большаков Валерий Петрович
Целитель
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Цикл романов Целитель. Компиляция. Книги 1-17

Третий Генерал: Тома I-II

Зот Бакалавр
1. Третий Генерал
Фантастика:
городское фэнтези
попаданцы
аниме
сказочная фантастика
5.00
рейтинг книги
Третий Генерал: Тома I-II

Черный Маг Императора 14

Герда Александр
14. Черный маг императора
Фантастика:
аниме
сказочная фантастика
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Черный Маг Императора 14

Андер Арес

Грехов Тимофей
1. Андер Арес
Фантастика:
рпг
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Андер Арес

Рассвет русского царства

Грехов Тимофей
1. Новая Русь
Документальная литература:
историческая литература
5.00
рейтинг книги
Рассвет русского царства

Буря империи

Сай Ярослав
6. Медорфенов
Фантастика:
аниме
фэнтези
фантастика: прочее
эпическая фантастика
5.00
рейтинг книги
Буря империи

Неправильный лекарь. Том 2

Измайлов Сергей
2. Неправильный лекарь
Фантастика:
городское фэнтези
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Неправильный лекарь. Том 2

Черный маг императора 3

Герда Александр
3. Черный маг императора
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Черный маг императора 3

Чехов

Гоблин (MeXXanik)
1. Адвокат Чехов
Фантастика:
фэнтези
боевая фантастика
альтернативная история
5.00
рейтинг книги
Чехов

Тринадцатый

NikL
1. Видящий смерть
Фантастика:
фэнтези
попаданцы
аниме
6.80
рейтинг книги
Тринадцатый

Антимаг его величества. Том IV

Петров Максим Николаевич
4. Модификант
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Антимаг его величества. Том IV