146
В борьбе за общий разделяемый ресурс, процессы входят в состояние состязания. Состояние состязания - ситуация, в которой два или более процессов считывают или записывают данные одновременно, а результат зависит от того, кто из них был первым.
Основной способ решения этих проблем - запрет на одновременное использование разделяемого ресурса или взаимное исключение.
Взаимное исключение предполагает, что одновременно не могут выполнять-я две
критические секции разных процессов.
Критической секцией (критической областью) называется часть кода процесса, который обеспечивает доступ к разделяемым ресурсам.
Чтобы сформулировать общую проблематику использования любых разделяемых ресурсов, были сформулированы четыре необходимых условия:
•два процесса не должны находиться в критических областях;
•в программе не должно быть предположений о скорости или количестве процессов;
•процесс, находящийся в критической области, не может блокировать другие процессы;
•невозможна ситуация, когда процесс вечно ждет попадания в критическую область.
Вабстрактном виде, нормальное поведение двух взаимодействующих процессов, удовлетворяющих этим условиям, можно показать рисунком 4.1.
Рисунок 4.1 - Нормальное взаимодействие двух процессов
Среди известных способов, реализующих взаимное исключение, можно выделить следующие:
147
•запрет всех прерываний, когда процесс вошел в критическую область;
•переменные блокировки, когда процесс, прежде чем войти в критическую
область, использует значение переменной, которая доступна всем процессам. Если значение переменной равно 0, то процесс изменяет ее значение на 1 и входит в критическую область, а если значение переменной равно 1, то процесс ждет, пока ее значение не изменится на 0;
•строгое чередование, когда процесс имеющий и использующий критическую
область становится в очередь и получает номер этой очереди, в цикле проверяя некоторую общую переменную, значение которой указывает номер очереди с разрешенным входм в критическую область. Когда процесс выходит из критической области он изменяет значение этой переменной, тем самым, разрешая другому процессу войти в критическую область.
•алгоритм Петерсона, который использует две функции enter_region(int
process) и leave_region(int process). Вызов первой, из этих функций, является обязательным условием, при входе процесса в критическую область. Она также сохраняет дополнительные данные о процессах, вызвавших ее, поэтому только один процесс может войти в критическую область, а другому необходимо ждать, когда выходящий из критической области процесс вызовет функцию leave_region(int process), освобождающую доступ к нужной области.
•команда TSL (Test and Set Lock — проверить и заблокировать), которая на
аппаратном уровне гарантирует неделимость операций чтения и записи слова памяти, обеспечивая однозначность отражения блокировки процессом разделяемого ресурса.
Не вдаваясь в детали возможных реализаций приведенных выше алгоритмов, мы рассмотрим пример простейшей проблемы разделения общих ресурсов.
Проблема производителя и потребителя, которая соотвествует взаимодействию двух процессов, использующих общий буфер данных (проблема ограни-ченного буфера).
Более конкретно:
•один из процессов, производитель, помещает данные в буфер;
•другой процесс, потребитель, читает данные из буфера;
•трудности начинаются, когда производитель хочет поместить данные в бу-
фер, а он уже заполнился; тогда производитель должен ждать, когда второй процесс, полностью или частично, не освободит буфер;
•аналогично, когда потребитель хочет прочитать данные из буфера, а он пуст,
процесс уходит в ожидание, пока другой процесс не положит данные в буфер и не разбудит потребителя.
Замечание
Указанная задача очень часто встречается даже в прикладном программировании, не говоря уже о системном, и требует разработки примитивов, обеспечивающих такое межпроцессное взаимодействие.
148
Ситуация значительно осложняется, когда процессу необходимо захватить несколько разделяемых ресурсов. В этом случае, возникает состояние взаимной блокировки.
Состояние взаимной блокировки возникает тогда, когда процесс успел захватить только часть разделяемых ресурсов, необходимых ему для выполнения работы, а другую часть захватили другие процессы.
В такой ситуации, все процессы переходят в состояние бесконечного ожидания необходимых им ресурсов.
Примером задачи, приводящей к взаимным блокировкам, является «Задача об обедающих философах», которую мы подробно рассмотрим в подразделе 4.5. Здесь же отметим, что в общем случае, необходимы дополнительные системные средства, обеспечивающие процессы инструментами надежной фиксации процессами фактов входа процессов в критические области и выхода из них.
Одним из первых системных средств, обеспечивающих программистов надежными инструментами работы с взаимодействующими процессами, стал пакет, имеющий название System V IPC. В последующем, его идеи были положены в средства сетевого взаимодействия ЭВМ.
Замечание
Следует хорошо осознать и запомнить, что все проблемы синхронизации процессов не могут быть решены алгоритмически только на уровне отдельного процесса. Это связано с тем, что алгоритм работы процесса прерывается ядром ОС, а захват нескольких нужных ресурсов процесса может осуществляться только некоторой последовательностью команд (системных вызовов), которые могут не завершиться до остановки процесса и передачи управления другому процессу.
Сцелью обеспечить системных и прикладных программистов надежным инструментом, устранения проблем взаимодействующих процессов, было разработано ряд системных средств ядра ОС, известных под общим названием System V IPC.
IPC (Inter Process Communication) — ориентирован на решение трех проблем:
•надежная и простая передача данных и сообщений от одного процесса другому;
•контроль над деятельностью процессов в критических ситуациях;
•согласование действий между процессами.
Непосредственная реализация пакета разделена на четыре части:
•средства адресации IPC, которые будут рассмотрены в данном подразделе;
•семафоры, обсуждаемые в подразделе 4.4;
•разделяемая память и очереди сообщений, подробно рассматриваемые в следующей теме.
149
Создавая пакет IPC, разработчики сразу предусмотрели возможность асинхронного взаимодействия процессов. Для этих целей была разработана система адресации, которой должен пользоваться каждый процесс, использующий средства пакета IPC.
Необходимость такой адресации обусловлена тем, что процессы должны различать разные виды взаимодействия, обусловленные их алгоритмами работы и прикладной направленностью процессов.
Вкачестве информационной основы формирования таких адресов используются:
•имена файлов, доступные в файловой системе ОС;
•произвольное целое число, отличное от нуля, интерпретируемое как номер проекта.
Системный вызов, создающий адрес (идентификатор, ключ) для пакета IPC, имеет вид:
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(char *pathname, int proj_id);
где pathname - должен являться указателем на имя существующего файла, доступного для процесса, вызывающего функцию;
proj_id – это небольшое целое число, характеризующее экземпляр средства связи.
В случае удачного завершения вызова возвращается значение созданного ключа типа key_t. При ошибке возвращается -1, а в переменную errno записывается код ошибки согласно системному вызову stat(2).
Замечание
Тип данных key_t обычно представляет собой 32-битовое целое.
Возвращаемое значение одинаково для всех имен, указывающих на один и тот же файл, при одинаковом значении proj_id. Возвращаемое значение должно отличаться, когда одновременно существующие файлы или идентификаторы проекта различаются.
Ядро ОС хранит информацию обо всех средствах System V IPC, использу-емых в системе, вне контекста пользовательских процессов. В прикладном плане, ключ, генерируемый функией ftok(...), рассматривается как средства связи между взаимодействующими процессами.
При создании нового средства связи или получении доступа к уже существующему, процесс получает неотрицательное целое число - дескриптор (идентификатор) этого средства связи, которое однозначно идентифицирует его во всей вычислительной системе. Этот дескриптор должен передаваться в качестве параметра всем системным вызовам, осуществляющим дальнейшие операции над соответствующим средством System V IPC.
150
Упользователя ОС, для работы со средствами межпроцессного взаимодействия System V IPC, имеются три основные утилиты, которыми следует пользо-ваться по мере необходимости:
•ipcmk — создание различных ресурсов средств IPC;
•ipcs - вывод отчёта о состоянии средств межпроцессного взаимодействия;
•ipcrm - удаление очередей сообщений, наборов семафоров и разделяемых сегментов памяти.
ipcmk [options]
ipcmk позволяет открывать разделяемые сегменты памяти, очереди сообщений и массивы семафоров.
Имеются следующие опции:
-M, --shmem size
Открытие разделяемого сегмента памяти размером size байт;
-Q, --queue
Открытие очереди сообщений;
-S, --semaphore number
Открытие массива семафоров с number элементами;
-p, --mode mode
Установка доступа к ресурсу; по-умолчанию = 0644;
-V, --version
Отображение версии пакета; -h, --help
ipcs [-abcmopqstMQSTy] [-C дамп] [-N система] [-u пользователь]
ipcs выводит информацию о системных средствам межпроцессного взаимодействия System V (IPC).
Имеются следующие опции (используйте ipcs -h, для конкретной системы):
-a Показать максимально возможное количество информации во время вывода данных об активных семафорах, очередях сообщений и разделяемых сегментах памяти. Это эквивалентно указанию опций -b, -c, -o, -p и -t.
-b Показать максимально допустимые размеры активных семафоров, очередей сообщений и разделяемых сегментов памяти. ``Максимальный допустимый размер'' -- это максимальное количество байт в сообщении в очереди сообщений, размер разделяемого сегмента памяти или количество семафо-