Студопедия  
Главная страница | Контакты | Случайная страница

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Написание, компиляция и запуск программы для организации двунаправленной связи между родственными процессами через pipe

Читайте также:
  1. A) Схватив окно за заголовок левой кнопкой мыши или через системное меню
  2. D) Факт взаимной неприязни между потерпевшим и его родственником.
  3. D. Между средним и промежуточным мозгом.
  4. ETerra: Вы сделали выбор между музыкой и предпринимательством в пользу предпринимательства?
  5. I)Однофакторный дисперсионный анализ (выполняется с применением программы «Однофакторный дисперсионный анализ» надстройки «Анализ данных» пакета Microsoft Excel).
  6. IBM получила первое в мире изображение отдельных связей между атомами углерода
  7. II категория. Проблемные кредитные организации
  8. II. Структура программы
  9. III Принципы организации производственных процессов
  10. III Санкт-Петербургского международного культурного форума

Pipe служит для организации однонаправленной или симплексной связи. Если бы в предыдущем примере мы попытались организовать через pipe двустороннюю связь, когда процесс-родитель пишет информацию в pipe, предполагая, что ее получит процесс-ребенок, а затем читает информацию из pip’а, предполагая, что ее записал порожденный процесс, то могла бы возникнуть ситуация, в которой процесс-родитель прочитал бы собственную информацию, а процесс-ребенок не получил бы ничего. Для использования одного pip’а в двух направлениях необходимы специальные средства синхронизации процессов, о которых говорилось на лекциях. Более простой способ организации двунаправленной связи между родственными процессами заключается в использовании двух pipe. Модифицируйте программу из предыдущего примера (раздел "Прогон программы для организации однонаправленной связи между родственными процессами через pipe") для организации такой двусторонней связи, откомпилируйте ее и запустите на исполнение.

Необходимо отметить, что в Solaris реализованы полностью дуплексные pip’ы. В этой системе для обоих файловых дескрипторов, ассоциированных с pip'ом, разрешены и операция чтения, и операция записи. Однако такое поведение не характерно для pip’ов и не является переносимым.

Особенности поведения вызовов read() и write() для pip'а

Системные вызовы read() и write() имеют определенные особенности поведения при работе с pip’ом, связанные с его ограниченным размером, задержками в передаче данных и возможностью блокирования обменивающихся информацией процессов. Организация запрета блокирования этих вызовов для pipe выходит за рамки нашего курса.

Будьте внимательны при написании программ, обменивающихся большими объемами информации через pipe. Помните, что за один раз из pip’а может прочитаться меньше информации, чем вы запрашивали, и за один раз в pipe может записаться меньше информации, чем вам хотелось бы. Проверяйте значения, возвращаемые вызовами!

Одна из особенностей поведения блокирующегося системного вызова read() связана с попыткой чтения из пустого pip'а. Если есть процессы, у которых этот pipe открыт для записи, то системный вызов блокируется и ждет появления информации. Если таких процессов нет, он вернет значение 0 без блокировки процесса. Эта особенность приводит к необходимости закрытия файлового дескриптора, ассоциированного с входным концом pip'a, в процессе, который будет использовать pipe для чтения ( close(fd[1] ) в процессе-ребенке в программе из раздела "Прогон программы для организации однонаправленной связи между родственными процессами через pipe"). Аналогичной особенностью поведения при отсутствии процессов, у которых pipe открыт для чтения, обладает и системный вызов write(), с чем связана необходимость закрытия файлового дескриптора, ассоциированного с выходным концом pip'a, в процессе, который будет использовать pipe для записи ( close(fd[0] ) в процессе-родителе в той же программе).

Системные вызовы read и write (продолжение) Особенности поведения при работе с pipe, FIFO и socket Системный вызов read
Ситуация Поведение
Попытка прочитать меньше байт, чем есть в наличии в канале связи. Читает требуемое количество байт и возвращает значение, соответствующее прочитанному количеству. Прочитанная информация удаляется из канала связи.
В канале связи находится меньше байт, чем затребовано, но не нулевое количество. Читает все, что есть в канале связи, и возвращает значение, соответствующее прочитанному количеству. Прочитанная информация удаляется из канала связи.
Попытка читать из канала связи, в котором нет информации. Блокировка вызова разрешена. Вызов блокируется до тех пор, пока не появится информация в канале связи и пока существует процесс, который может передать в него информацию. Если информация появилась, то процесс разблокируется, и поведение вызова определяется двумя предыдущими строками таблицы. Если в канал некому передать данные (нет ни одного процесса, у которого этот канал связи открыт для записи), то вызов возвращает значение 0. Если канал связи полностью закрывается для записи во время блокировки читающего процесса, то процесс разблокируется, и системный вызов возвращает значение 0.
Попытка читать из канала связи, в котором нет информации. Блокировка вызова не разрешена. Если есть процессы, у которых канал связи открыт для записи, системный вызов возвращает значение -1 и устанавливает переменную errno в значение EAGAIN. Если таких процессов нет, системный вызов возвращает значение 0.
  Системный вызов write
Ситуация Поведение
Попытка записать в канал связи меньше байт, чем осталось до его заполнения. Требуемое количество байт помещается в канал связи, возвращается записанное количество байт.
Попытка записать в канал связи больше байт, чем осталось до его заполнения. Блокировка вызова разрешена. Вызов блокируется до тех пор, пока все данные не будут помещены в канал связи. Если размер буфера канала связи меньше, чем передаваемое количество информации, то вызов тем самым будет ждать, пока часть информации не будет считана из канала связи. Возвращается записанное количество байт.
Попытка записать в канал связи больше байт, чем осталось до его заполнения, но меньше, чем размер буфера канала связи. Блокировка вызова запрещена. Системный вызов возвращает значение -1 и устанавливает переменную errno в значение EAGAIN.
В канале связи есть место. Попытка записать в канал связи больше байт, чем осталось до его заполнения, и больше, чем размер буфера канала связи. Блокировка вызова запрещена. Записывается столько байт, сколько осталось до заполнения канала. Системный вызов возвращает количество записанных байт.
Попытка записи в канал связи, в котором нет места. Блокировка вызова не разрешена. Системный вызов возвращает значение -1 и устанавливает переменную errno в значение EAGAIN.
Попытка записи в канал связи, из которого некому больше читать, или полное закрытие канала на чтение во время блокировки системного вызова. Если вызов был заблокирован, то он разблокируется. Процесс получает сигнал SIGPIPE. Если этот сигнал обрабатывается пользователем, то системный вызов вернет значение -1 и установит переменную errno в значение EPIPE.
Необходимо отметить дополнительную особенность системного вызова write при работе с pip’ами и FIFO. Запись информации, размер которой не превышает размер буфера, должна осуществляться атомарно – одним подряд лежащим куском. Этим объясняется ряд блокировок и ошибок в предыдущем перечне.

Задача повышенной сложности: определите размер pipe для вашей операционной системы.

Понятие FIFO. Использование системного вызова mknod() для создания FIFO. Функция mkfifo()

Доступ к информации о расположении pip'а в операционной системе и его состоянии может быть осуществлен только через таблицу открытых файлов процесса, создавшего pipe, и через унаследованные от него таблицы открытых файлов процессов-потомков. Поэтому изложенный выше механизм обмена информацией через pipe справедлив лишь для родственных процессов, имеющих общего прародителя, инициировавшего системный вызов pipe(), или для таких процессов и самого прародителя и не может использоваться для потокового общения с другими процессами.

Для организации потокового взаимодействия любых процессов в операционной системе UNIX применяется средство связи, получившее название FIFO (от First Input First Output) или именованный pipe. FIFO во всем подобен pip’у, за одним исключением: данные о расположении FIFO в адресном пространстве ядра и его состоянии процессы могут получать не через родственные связи, а через файловую систему. Для этого при создании именованного pip’а на диске заводится файл специального типа, обращаясь к которому процессы могут получить интересующую их информацию. Для создания FIFO используется системный вызов mknod() или существующая в некоторых версиях UNIX функция mkfifo().

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

После открытия именованный pipe ведет себя точно так же, как и неименованный. Для дальнейшей работы с ним применяются системные вызовы read(), write() и close(). Время существования FIFO в адресном пространстве ядра операционной системы, как и в случае с pip’ом, не может превышать время жизни последнего из использовавших его процессов. Когда все процессы, работающие с FIFO, закрывают все файловые дескрипторы, ассоциированные с ним, система освобождает ресурсы, выделенные под FIFO. Вся непрочитанная информация теряется. В то же время файл-метка остается на диске и может использоваться для новой реальной организации FIFO в да льнейшем.

Использование системного вызова mknod для создания FIFO Прототип системного вызова #include <sys/stat.h> #include <unistd.h> int mknod(char *path, int mode, int dev); Описание системного вызова Нашей целью является не полное описание системного вызова mknod, а только описание его использования для создания FIFO. Поэтому мы будем рассматривать не все возможные варианты задания параметров, а только те из них, которые соответствуют этой специфической деятельности. Параметр dev является несущественным в нашей ситуации, и мы будем всегда задавать его равным 0. Параметр path является указателем на строку, содержащую полное или относительное имя файла, который будет являться меткой FIFO на диске. Для успешного создания FIFO файла с таким именем перед вызовом существовать не должно. Параметр mode устанавливает атрибуты прав доступа различных категорий пользователей к FIFO. Этот параметр задается как результат побитовой операции "или" значения S_IFIFO, указывающего, что системный вызов должен создать FIFO, и некоторой суммы следующих восьмеричных значений:
  • 0400 – разрешено чтение для пользователя, создавшего FIFO;
  • 0200 – разрешена запись для пользователя, создавшего FIFO;
  • 0040 – разрешено чтение для группы пользователя, создавшего FIFO;
  • 0020 – разрешена запись для группы пользователя, создавшего FIFO;
  • 0004 – разрешено чтение для всех остальных пользователей;
  • 0002 – разрешена запись для всех остальных пользователей.
При создании FIFO реально устанавливаемые права доступа получаются из стандартной комбинации параметра mode и маски создания файлов текущего процесса umask, а именно – они равны (0777 & mode) & ~umask. Возвращаемые значения При успешном создании FIFO системный вызов возвращает значение 0, при неуспешном – отрицательное значение.
Функция mkfifo Прототип функции #include <sys/stat.h> #include <unistd.h> int mkfifo(char *path, int mode); Описание функции Функция mkfifo предназначена для создания FIFO в операционной системе. Параметр path является указателем на строку, содержащую полное или относительное имя файла, который будет являться меткой FIFO на диске. Для успешного создания FIFO файла с таким именем перед вызовом функции не должно существовать. Параметр mode устанавливает атрибуты прав доступа различных категорий пользователей к FIFO. Этот параметр задается как некоторая сумма следующих восьмеричных значений:
  • 0400 – разрешено чтение для пользователя, создавшего FIFO;
  • 0200 – разрешена запись для пользователя, создавшего FIFO;
  • 0040 – разрешено чтение для группы пользователя, создавшего FIFO;
  • 0020 – разрешена запись для группы пользователя, создавшего FIFO;
  • 0004 – разрешено чтение для всех остальных пользователей;
  • 0002 – разрешена запись для всех остальных пользователей.
При создании FIFO реально устанавливаемые права доступа получаются из стандартной комбинации параметра mode и маски создания файлов текущего процесса umask, а именно – они равны (0777 & mode) & ~umask. Возвращаемые значения При успешном создании FIFO функция возвращает значение 0, при неуспешном – отрицательное значение.

Важно понимать, что файл типа FIFO не служит для размещения на диске информации, которая записывается в именованный pipe. Эта информация располагается внутри адресного пространства операционной системы, а файл является только меткой, создающей предпосылки для ее размещения.




Дата добавления: 2014-12-19; просмотров: 56 | Поможем написать вашу работу | Нарушение авторских прав




lektsii.net - Лекции.Нет - 2014-2024 год. (0.008 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав