Мьютексы в пакете Pthreads

Пакет Pthreads предоставляет ряд функций, которые могут быть использованы для синхронизации потоков. Основным механизмом является использование переменных — мьютексов, предназначенных для защиты каждой критической области.
Каждая такая переменная может быть в заблокированном или незаблокированном состоянии. Поток, которому необходимо войти в критическую область, сначала пытается заблокировать соответствующий мьютекс. Если мьютекс не заблокирован, поток может войти в критическую область беспрепятственно и заблокировать мьютекс в одном неделимом действии, не позволяя войти в нее другим потокам. Если мьютекс уже заблокирован, вызывающий поток блокируется до тех пор, пока не разблокируется мьютекс. Если разблокировки одного и того же мьютекса ожидают несколько потоков, возможность возобновить работу и заново заблокировать мьютекс предоставляется только одному из них. Эти блокировки не являются обязательными. Соблюдение порядка их использования потоками всецело возложено на программиста.

Основные вызовы, связанные с мьютексами, показаны в табл. 2.6. Как и ожидалось, мьютексы могут создаваться и уничтожаться. Вызовы, осуществляющие эти операции, называются, соответственно, pthread_mutex_init и pthread_mutex_destroy. Мьютексы также могут быть заблокированы вызовом pthread_mutex_lock, который пытается завладеть блокировкой и блокирует выполнение потока, если мьютекс уже заблокирован. Есть также вызов, используемый для попытки заблокировать мьютекс и безуспешного выхода с кодом ошибки, если мьютекс уже был заблокирован. Этот вызов называется pthread_mutex_trylock. Он позволяет потоку организовать эффективное активное ожидание, если в таковом возникнет необходимость. И наконец, вызов pthread_mutex_ unlock разблокирует мьютекс и возобновляет работу только одного потока, если имеется один или более потоков, ожидающих разблокирования. Мьютексы могут иметь также атрибуты, но они используются только для решения специализированных задач.

Таблица 2.6. Ряд вызовов пакета Pthreads, имеющих отношение к мьютексам


В дополнение к мьютексам пакет Pthreads предлагает второй механизм синхронизации — условные переменные. Мьютексы хороши для разрешения или блокирования доступа к критической области. Условные переменные позволяют потокам блокироваться до выполнения конкретных условий. Эти два метода практически всегда используются вместе. Теперь давайте более пристально взглянем на взаимодействие потоков, мьютексов и условных переменных.

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

Наиболее важные вызовы, связанные с условными переменными, показаны в табл. 2.7. Согласно вашим возможным ожиданиям, в ней представлены вызовы, предназначенные для создания и уничтожения условных переменных.

У них могут быть атрибуты, для управления которыми существует ряд других (не показанных в таблице) вызовов. Первичные операции над условными переменными осуществляются с помощью вызовов pthread_cond_wait и pthread_cond_signal. Первый из них блокирует вызывающий поток до тех пор, пока не будет получен сигнал от другого потока (использующего второй вызов). Разумеется, основания для блокирования и ожидания не являются частью протокола ожиданий и отправки сигналов. Заблокированный поток зачастую ожидает, пока сигнализирующий поток не совершит определенную работу, не освободит какие-то ресурсы или не выполнит какие-нибудь другие действия. Только после этого заблокированный поток продолжает свою работу. Условные переменные позволяют осуществлять это ожидание и блокирование как неделимые операции. Вызов pthread_cond_broadcast используется в том случае, если есть потенциальная возможность находиться в заблокированном состоянии и ожидании одного и того же сигнала сразу нескольким потокам.

Таблица 2.7. Ряд вызовов пакета Pthreads, имеющих отношение к условным переменным


Условные переменные и мьютексы всегда используются вместе. Схема для одного потока состоит в блокировании мьютекса, а затем в ожидании на основе значения условной переменной, если поток не может получить то, что ему требуется. Со временем другой поток подаст ему сигнал, и он сможет продолжить работу. Вызов pthread_cond_wait осуществляется неделимо и выполняет разблокирование удерживаемого мьютекса как одну неделимую и непрерываемую операцию. По этой причине мьютекс является одним из его аргументов.

Также стоит заметить, что условные переменные (в отличие от семафоров) не запоминаются. Если сигнал отправлен условной переменной, изменения значения которой не ожидает ни один из потоков, сигнал теряется. Чтобы не потерять сигнал, программисты должны обращать особое внимание.

В качестве примера использования мьютексов и условных переменных в листинге 2.8 показана очень простая задача производителя-потребителя, в которой используется один- единственный буфер. Когда производитель заполняет буфер, то перед тем как произвести следующую запись, он должен ждать, пока потребитель не опустошит этот буфер. Точно так же, когда потребитель извлечет запись, он должен ждать, пока производитель не произведет другую запись. При всей своей предельной простоте этот пример иллюстрирует работу основного механизма. Оператор, приостанавливающий работу потока, прежде чем продолжить его работу, должен убедиться в выполнении условия, поскольку поток может быть активирован в результате поступления сигнала UNIX или по другой причине.

Листинг 2.8. Использование потоков для решения задачи производителя- потребителя


pthread_mutex_t the_mutex;

pthread_cond_t condc, condp; /* используется для сигнализации */

int buffer = 0; /* буфер, используемый между производителем и

потребителем */

void *producer(void *ptr) /* производство данных */

{ int i;

for (i= 1; i

<< | >>
Источник: Э. ТАНЕНБАУМ Х. БОС. СОВРЕМЕННЫЕ ОПЕРАЦИОННЫЕ СИСТЕМ Ы 4-е ИЗДАНИЕ. 2015

Еще по теме Мьютексы в пакете Pthreads:

  1. Глава 24 СОЗИДАНИЕ И ОТКРЫТИЕ СЕРДЦА В ОДНОМ ПАКЕТЕ
  2. Могу
  3. Сергей Супрунов. FreeBSD - полезные советы, 2010
  4. Тема 12. Иконологическое моделирование социальных процессов
  5. Познакомьтесь с Крайоном Глава первая Кто я?
  6. Общая собственность: понятие, виды
  7. I. На что мы обречены при излишках веса
  8. А. Н. Степанов. Информатика Базовый курс для студентов гуманитарных специальностей высших учебных заведений 6-е издание, 2010
  9. 1. Продажа предприятий и иные формы их приобретения
  10. 4. Продажа приватизируемых объектов на аукционах и конкурсах
  11. Горьковская, или нижегородская, «школа» воров.
  12. ТРЕТИЙ ДЕНЬ
  13. Глава 15 МИР, В КОТОРОМ НЕ СТРАШНО ЛЮБИТЬ ДРУГ ДРУГА
  14. 3. Функции учредительного договора
  15. Новейшая концепция самореализации и организации деятельности.
  16. Новейшая концепция самореализации и организации деятельности.