Основы многопоточного и распределенного программирования

Синхронизация типа "производитель-потребитель"


В последнем решении раздела 2.2 для задачи поиска шаблонов в файле использованы про­цесс-производитель и процесс-потребитель. Производитель постоянно считывает строки ввода, определяет, какие из них содержат искомый шаблон, и передает их процессу-потребителю. За­тем потребитель выводит строки, полученные от производителя. Взаимодействие между произ­водителем и потребителем обеспечивается с помощью разделяемой переменной buffer. Метод синхронизации доступа к буферу остался неопределенным, и теперь его можно описать.

Здесь решается более простая задача типа "производитель-потребитель": копирование всех элементов массива от производителя к потребителю. Адаптация этого решения к кон-, кретной задаче из раздела 2.2 оставляется читателю (см. упражнения в конце этой главы).

Даны два процесса: Producer (производитель) и Consumer (потребитель). Процесс Pro­ducer имеет локальный массив целых чисел a [n]; Consumer — b [n]. Предполагается, что массив а инициализирован. Цель — скопировать его содержимое в массив Ь. Поскольку про­цессы не разделяют массивы, для их взаимодействия нужны разделяемые переменные. Пусть переменная buf — это одиночная разделяемая целочисленная переменная, которая будет служить буфером взаимодействия.

Процессы Producer и Consumer должны получать доступ к переменной buf по очереди. Сначала Producer помещает первый элемент массива а в переменную buf, затем Consumer извлекает ее, потом Producer помещает в переменную buf следующий элемент массива а и так далее. Пусть разделяемые переменные рис будут счетчиками числа помещенных и из­влеченных элементов, соответственно. Их начальные значения — 0. Тогда условия синхрони­зации процессов Producer и Consumer могут быть записаны в следующем виде: PC: с <= р <= с+1

Значения переменных сир могут отличаться не больше, чем на 1; это значит, что Producer поместил в буфер максимум на один элемент больше, чем Consumer извлек. Код этих двух процессов приведен в листинге 2.2.

Процессы Producer и Consumer используют переменные рис (см. листинг 2.2) для син­хронизации доступа к буферу buf. Операторы await применяются для приостановки процес­сов до тех пор, пока буфер не станет полным или пустым. Если истинно условие р == с, буфер пуст (последний помещенный в него элемент был извлечен), а если р > с — заполнен.

Если синхронизация реализуется описанным способом, говорят, что процесс находится в состоянии активного ожидания, или зациклен, поскольку он занят проверкой условия в опе­раторе await, но все, что он делает, — это повторение цикла до тех пор, пока условие не вы-



Содержание раздела