кции. Если структура обнаружена, ядро вычитает значение произведенной над семафором операции из установочного значения. Таким образом, в структуре восстановле- ния хранится результат вычитания суммы значений всех операций, произведенных над семафором, для которого установлен флаг SEM_UNDO. Если соответствующей структуры нет, ядро создает ее, сортируя при этом список структур по иденти- фикаторам и номерам семафоров. Если установочное значение становится равным 0, ядро удаляет структуру из списка. Когда процесс завершается, ядро вызыва- +---------------++-------+ +---------------++-------+-------+ | идентификатор || | | идентификатор || | | | семафора || semid | | семафора || semid | semid | +---------------++-------+ +---------------++-------+-------+ | номер семафора|| 0 | | номер семафора|| 0 | 1 | +---------------++-------+ +---------------++-------+-------+ | установочное || | | установочное || | | | значение || 1 | | значение || 1 | 1 | +---------------++-------+ +---------------++-------+-------+ (а) После первой операции (б) После второй операции +---------------++-------+ | идентификатор || | | семафора || semid | +---------------++-------+ | номер семафора|| 0 | пусто +---------------++-------+ | установочное || | | значение || 1 | +---------------++-------+ (в) После третьей операции (г) После четвертой операции Рисунок 11.17. Последовательность состояний списка структур восстановления 352 ет специальную процедуру, которая просматривает все связанные с процессом структуры восстановления и выполняет над указанным семафором все обусловлен- ные действия. Ядро создает структуру восстановления всякий раз, когда процесс уменьша- ет значение семафора, а удаляет ее, когда процесс увеличивает значение сема- фора, поскольку установочное значение структуры равно 0. На Рисунке 11.17 показана последовательность состояний списка структур при выполнении программы с параметром 'a'. После первой опе- рации процесс имеет одну структуру, состоящую из идентификатора semid, номе- ра семафора, равного 0, и установочного значения, равного 1, а после второй операции появляется вторая структура с номером семафора, равным 1, и устано- вочным значением, равным 1. Если процесс неожиданно завершается, ядро прохо- дит по всем структурам и прибавляет к каждому семафору по единице, восста- навливая их значения в 0. В частном случае ядро уменьшает установочное зна- чение для семафора 1 на третьей операции, в соответствии с увеличением зна- чения самого семафора, и удаляет всю структуру целиком, поскольку установоч- ное значение становится нулевым. После четвертой операции у процесса больше нет структур восстановления, поскольку все установочные значения стали нуле- выми. Векторные операции над семафорами позволяют избежать взаимных блокиро- вок, как было показано выше, однако они представляют известную трудность для понимания и реализации, и в большинстве приложений полный набор их возмож- ностей не является обязательным. Программы, испытывающие потребность в ис- пользовании набора семафоров, сталкиваются с возникновением взаимных блоки- ровок на пользовательском уровне, и ядру уже нет необходимости поддерживать такие сложные формы системных функций. Синтаксис вызова системной функции semctl: semctl(id,number,cmd,arg); Параметр arg объявлен как объединение типов данных: union semunion { int val; struct semid_ds *semstat; /* описание типов см. в При- * ложении */ unsigned short *array; } arg; Ядро интерпретирует параметр arg в зависимости от значения параметра cmd, подобно тому, как интерпретирует команды ioctl (глава 10). Типы дейст- вий, которые могут использоваться в параметре cmd: получить или установить значения управляющих параметров (права доступа и др.), установить значения одного или всех семафоров в наборе, прочитать значения семафоров. Подробнос- ти по каждому действию содержатся в Приложении. Если указана команда удале- ния, IPC_RMID, ядро ведет поиск всех процессов, содержащих структуры восста- новления для данного семафора, и удаляет соответствующие структуры из систе- мы. Затем ядро инициализирует используемые семафором структуры данных и вы- водит из состояния приостанова все процессы, ожидающие наступления некоторо- го связанного с семафором события: когда процессы возобновляют свое выполне- ние, они обнаруживают, что идентификатор семафора больше не является коррек- тным, и возвращают вызывающей программе ошибку. 11.2.4 Общие замечания Механизм функционирования файловой системы и механизмы взаимодействия 353 процессов имеют ряд общих черт. Системные функции типа "get" похожи на функ- ции creat и open, функции типа "control" предоставляют возможность удалять дескрипторы из системы, чем похожи на функцию unlink. Тем не менее, в меха- низмах взаимодействия процессов отсутствуют операции, аналогичные операциям, выполняемым системной функцией close. Следовательно, ядро не располагает сведениями о том, какие процессы могут использовать механизм IPC, и, дейст- вительно, процессы могут прибегать к услугам этого механизма, если правильно угадывают соответствующий идентификатор и если у них имеются необходимые права доступа, даже если они не выполнили предварительно функцию типа "get". Ядро не может автоматически очищать неиспользуемые структуры механизма взаи- модействия процессов, поскольку ядру неизвестно, какие из этих структур больше не нужны. Таким образом, завершившиеся вследствие возникновения ошиб- ки процессы могут оставить после себя ненужные и неиспользуемые структуры, перегружающие и засоряющие систему. Несмотря на то, что в структурах меха- низма взаимодействия после завершения существования процесса ядро может сох- ранить информацию о состоянии и данные, лучше все-таки для этих целей ис- пользовать файлы. Вместо традиционных, получивших широкое распространение файлов механизмы взаимодействия процессов используют новое пространство имен, состоящее из ключей (keys). Расширить семантику ключей на всю сеть довольно трудно, пос- кольку на разных машинах ключи могут описывать различные объекты. Короче го- воря, ключи в основном предназначены для использования в одномашинных систе- мах. Имена файлов в большей степени подходят для распределенных систем (см. главу 13). Использование ключей вместо имен файлов также свидетельствует о том, что средства взаимодействия процессов являются "вещью в себе", полезной в специальных приложениях, но не имеющей тех возможностей, которыми облада- ют, например, каналы и файлы. Большая часть функциональных возможностей, предоставляемых данными средствами, может быть реализована с помощью других системных средств, поэтому включать их в состав ядра вряд ли следовало бы. Тем не менее, их использование в составе пакетов прикладных программ тесного взаимодействия дает лучшие результаты по сравнению со стандартными файловыми средствами (см. Упражнения). 11.3 ВЗАИМОДЕЙСТВИЕ В СЕТИ Программы, поддерживающие межмашинную связь, такие, как электронная поч- та, программы дистанционной пересылки файлов и удаленной регистрации, издав- на используются в качестве специальных средств организации подключений и ин- формационного обмена. Так, например, стандартные программы, работающие в составе электронной почты, сохраняют текст почтовых сообщений пользователя в отдельном файле (для пользователя "mjb" этот файл имеет имя "/usr/mail/mjb"). Когда один пользователь посылает другому почтовое сообще- ние на ту же машину, программа mail (почта) добавляет сообщение в конец фай- ла адресата, используя в целях сохранения целостности различные блокирующие и временные файлы. Когда адресат получает почту, программа mail открывает принадлежащий ему почтовый файл и читает сообщения. Для того, чтобы послать сообщение на другую машину, программа mail должна в конечном итоге отыскать на ней соответствующий почтовый файл. Поскольку программа не может работать с удаленными файлами непосредственно, процесс, протекающий на другой машине, должен действовать в качестве агента локального почтового процесса; следова- тельно, локальному процессу необходим способ связи со своим удаленным аген- том через межмашинные границы. Локальный процесс является клиентом удаленно- го обслуживающего (серверного) процесса. Поскольку в системе UNIX новые процессы создаются с помощью системной функции fork, к тому моменту, когда клиент попытается выполнить подключение, обслуживающий процесс уже должен существовать. Если бы в момент создания но- вого процесса удаленное ядро получало запрос на подключение (по каналам меж- машинной связи), возникла бы несогласованность с архитектурой системы. Чтобы 354 избежать этого, некий процесс, обычно init, порождает обслуживающий процесс, который ведет чтение из канала связи, пока не получает запрос на обслужива- ние, после чего в соответствии с некоторым протоколом выполняет установку соединения. Выбор сетевых средств и протоколов обычно выполняют программы клиента и сервера, основываясь на информации, хранящейся в прикладных базах данных; с другой стороны, выбранные пользователем средства могут быть зако- дированы в самих программах. В качестве примера рассмотрим программу uucp, которая обслуживает пере- сылку файлов в сети и исполнение команд на удалении (см. [Nowitz 80]). Про- цесс-клиент запрашивает в базе данных адрес и другую маршрутную информацию (например, номер телефона), открывает автокоммутатор, записывает или прове- ряет информацию в дескрипторе открываемого файла и вызывает удаленную маши- ну. Удаленная машина может иметь специальные линии, выделенные для использо- вания программой uucp; выполняющийся на этой машине процесс init порождает getty-процессы - серверы, которые управляют линиями и получают извещения о подключениях. После выполнения аппаратного подключения процесс-клиент регис- трируется в системе в соответствии с обычным протоколом регистрации: getty-процесс запускает специальный интерпретатор команд, uucico, указанный в файле "/etc/passwd", а процесс-клиент передает на удаленную машину после- довательность команд, тем самым заставляя ее исполнять процессы от имени ло- кальной машины. Сетевое взаимодействие в системе UNIX представляет серьезную проблему, поскольку сообщения должны включать в себя как информационную, так и управ- ляющую части. В управляющей части сообщения может располагаться адрес назна- чения сообщения. В свою очередь, структура адресных данных зависит от типа сети и используемого протокола. Следовательно, процессам нужно знать тип се- ти, а это идет вразрез с тем принципом, по которому пользователи не должны обращать внимания на тип файла, ибо все устройства для пользователей выгля- дят как файлы. Традиционные методы реализации сетевого взаимодействия при установке управляющих параметров в сильной степени полагаются на помощь сис- темной функции ioctl, однако в разных типах сетей этот момент воплощается по-разному. Отсюда возникает нежелательный побочный эффект, связанный с тем, что программы, разработанные для одной сети, в других сетях могут не зарабо- тать. Чтобы разработать сетевые интерфейсы для системы UNIX, были предприняты значительные усилия. Реализация потоков в последних редакциях версии V рас- полагает элегантным механизмом поддержки сетевого взаимодействия, обеспечи- вающим гибкое сочетание отдельных модулей протоколов и их согласованное ис- пользование на уровне задач. Следующий раздел посвящен краткому описанию ме- тода решения данных проблем в системе BSD, основанного на использовании гнезд. 11.4 ГНЕЗДА В предыдущем разделе было показано, каким образом взаимодействуют между собой процессы, протекающие на разных машинах, при этом обращалось внимание на то, что способы реализации взаимодействия могут быть различаться в зави- симости от используемых протоколов и сетевых средств. Более того, эти спосо- бы не всегда применимы для обслуживания взаимодействия процессов, выполняю- щихся на одной и той же машине, поскольку в них предполагается существование обслуживающего (серверного) процесса, который при выполнении системных функ- ций open или read будет приостанавливаться драйвером. В целях создания более универсальных методов взаимодействия процессов на основе использования мно- гоуровневых сетевых протоколов для системы BSD был разработан механизм, по- лучивший название "sockets" (гнезда) (см. [Berkeley 83]). В данном разделе мы рассмотрим некоторые аспекты применения гнезд (на пользовательском уровне представления). 355 Процесс-клиент Процесс-сервер | | +--+ +--+ +-------------------------+--+ +--+--------------------------+ | Уровень гнезд | | Уровень гнезд | +-------------------------+--+ +--+--------------------------+ | TCP | | TCP | | Уровень протоколов | | | | Уровень протоколов | | IP | | IP | +-------------------------+--+ +--+--------------------------+ | Драйвер| | Драйвер | | Уровень устройств Ethernet| |Ethernet Уровень устройств | +-------------------------+--+ +--+--------------------------+ +---+ +---+ | | С е т ь Рисунок 11.18. Модель с использованием гнезд Структура ядра имеет три уровня: гнезд, протоколов и устройств (Рисунок 11.18). Уровень гнезд выполняет функции интерфейса между обращениями к опе- рационной системе (системным функциям) и средствами низких уровней, уровень протоколов содержит модули, обеспечивающие взаимодействие процессов (на ри- сунке упомянуты протоколы TCP и IP), а уровень устройств содержит драйверы, управляющие сетевыми устройствами. Допустимые сочетания протоколов и драйве- ров указываются при построении системы (в секции конфигурации); этот способ уступает по гибкости вышеупомянутому потоковому механизму. Процессы взаимо- действуют между собой по схеме клиент-сервер: сервер ждет сигнала от гнезда, находясь на одном конце дуплексной линии связи, а процессы-клиенты взаимо- действуют с сервером через гнездо, находящееся на другом конце, который мо- жет располагаться на другой машине. Ядро обеспечивает внутреннюю связь и пе- редает данные от клиента к серверу. Гнезда, обладающие одинаковыми свойствами, например, опирающиеся на об- щие соглашения по идентификации и форматы адресов (в протоколах), группиру- ются в домены (управляемые одним узлом). В системе BSD 4.2 поддерживаются домены: "UNIX system" - для взаимодействия процессов внутри одной машины и "Internet" (межсетевой) - для взаимодействия через сеть с помощью протокола DARPA (Управление перспективных исследований и разработок Министерства обо- роны США) (см. [Postel 80] и [Postel 81]). Гнезда бывают двух типов: вирту- альный канал (потоковое гнездо, если пользоваться терминологией Беркли) и дейтаграмма. Виртуальный канал обеспечивает надежную доставку данных с сох- ранением исходной последовательности. Дейтаграммы не гарантируют надежную доставку с сохранением уникальности и последовательности, но они более эко- номны в смысле использования ресурсов, поскольку для них не требуются слож- ные установочные операции; таким образом, дейтаграммы полезны в отдельных случаях взаимодействия. Для каждой допустимой комбинации типа домен-гнездо в системе поддерживается умолчание на используемый протокол. Так, например, для домена "Internet" услуги виртуального канала выполняет протокол транс- портной связи (TCP), а функции дейтаграммы - пользовательский дейтаграммный протокол (UDP). Существует несколько системных функций работы с гнездами. Функция socket устанавливает оконечную точку линии связи. sd = socket(format,type,protocol); Format обозначает домен ("UNIX system" или "Internet"), type - тип связи че- рез гнездо (виртуальный канал или дейтаграмма), а protocol - тип протокола, управляющего взаимодействием. Дескриптор гнезда sd, возвращаемый функцией socket, используется другими системными функциями. Закрытие гнезд выполняет 356 функция close. Функция bind связывает дескриптор гнезда с именем: bind(sd,address,length); где sd - дескриптор гнезда, address - адрес структуры, определяющей иденти- фикатор, характерный для данной комбинации домена и протокола (в функции socket). Length - длина структуры address; без этого параметра ядро не знало бы, какова длина структуры, поскольку для разных доменов и протоколов она может быть различной. Например, для домена "UNIX system" структура содержит имя файла. Процессы-серверы связывают гнезда с именами и объявляют о состо- явшемся присвоении имен процессам-клиентам. С помощью системной функции connect делается запрос на подключение к су- ществующему гнезду: connect(sd,address,length); Семантический смысл параметров функции остается прежним (см. функцию bind), но address указывает уже на выходное гнездо, образующее противоположный ко- нец линии связи. Оба гнезда должны использовать одни и те же домен и прото- кол связи, и тогда ядро удостоверит правильность установки линии связи. Если тип гнезда - дейтаграмма, сообщаемый функцией connect ядру адрес будет ис- пользоваться в последующих обращениях к функции send через данное гнездо; в момент вызова никаких соединений не производится. Пока процесс-сервер готовится к приему связи по виртуальному каналу, яд- ру следует выстроить поступающие запросы в очередь на обслуживание. Макси- мальная длина очереди задается с помощью системной функции listen: listen(sd,qlength) где sd - дескриптор гнезда, а qlength - максимально-допустимое число запро- сов, ожидающих обработки. +--------------------+ +-------------------------+ | Процесс-клиент | | Процесс-сервер | | | | | | - | | | | | +----+ ------ | | | | | | - | | | | |listen addr accept addr| +---------+----------+ +-----+-------------------+ | | - +--------------------------+------------- Рисунок 11.19. Прием вызова сервером Системная функция accept принимает запросы на подключение, поступающие на вход процесса-сервера: nsd = accept(sd,address,addrlen); где sd - дескриптор гнезда, address - указатель на пользовательский массив, в котором ядро возвращает адрес подключаемого клиента, addrlen - размер пользовательского массива. По завершении выполнения функции ядро записывает в переменную addrlen размер пространства, фактически занятого массивом. Фун- кция возвращает новый дескриптор гнезда (nsd), отличный от дескриптора sd. Процесс-сервер может продолжать слежение за состоянием объявленного гнезда, поддерживая связь с клиентом по отдельному каналу (Рисунок 11.19). 357 Функции send и recv выполняют передачу данных через подключенное гнездо. Синтаксис вызова функции send: count = send(sd,msg,length,flags); где sd - дескриптор гнезда, msg - указатель на посылаемые данные, length - размер данных, count - количество фактически переданных байт. Параметр flags может содержать значение SOF_OOB (послать данные out-of-band - "через тамож- ню"), если посылаемые данные не учитываются в общем информационном обмене между взаимодействующими процессами. Программа удаленной регистрации, напри- мер, может послать out-of-band сообщение, имитирующее нажатие на клавиатуре терминала клавиши "delete". Синтаксис вызова системной функции recv: count = recv(sd,buf,length,flags); где buf - массив для приема данных, length - ожидаемый объем данных, count - количество байт, фактически переданных пользовательской программе. Флаги (flags) могут быть установлены таким образом, что поступившее сообщение пос- ле чтения и анализа его содержимого не будет удалено из очереди, или настро- ены на получение данных out-of-band. В дейтаграммных версиях указанных функ- ций, sendto и recvfrom, в качестве дополнительных параметров указываются ад- реса. После выполнения подключения к гнездам потокового типа процессы могут вместо функций send и recv использовать функции read и write. Таким образом, согласовав тип протокола, серверы могли бы порождать процессы, работающие только с функциями read и write, словно имеют дело с обычными файлами. Функция shutdown закрывает гнездовую связь: shutdown(sd,mode) где mode указывает, какой из сторон (посылающей, принимающей или обеим вмес- те) отныне запрещено участие в процессе передачи данных. Функция сообщает используемому протоколу о завершении сеанса сетевого взаимодействия, остав- ляя, тем не менее, дескрипторы гнезд в неприкосновенности. Освобождается дескриптор гнезда только в результате выполнения функции close. Системная функция getsockname получает имя гнездовой связи, установлен- ной ранее с помощью функции bind: getsockname(sd,name,length); Функции getsockopt и setsockopt получают и устанавливают значения раз- личных связанных с гнездом параметров в соответствии с типом домена и прото- кола. Рассмотрим обслуживающую программу, представленную на Рисунке 11.20. Процесс создает в домене "UNIX system" гнездо потокового типа и присваивает ему имя sockname. Затем с помощью функции listen устанавливается длина оче- реди поступающих сообщений и начинается цикл ожидания поступления запросов. Функция accept приостанавливает свое выполнение до тех пор, пока протоколом не будет зарегистрирован запрос на подключение к гнезду с означенным именем; после этого функция завершается, возвращая поступившему запросу новый деск- риптор гнезда. Процесс-сервер порождает потомка, через которого будет под- держиваться связь с процессом-клиентом; родитель и потомок при этом закрыва- ют свои дескрипторы, чтобы они не становились помехой для коммуникационного траффика другого процесса. Процесс-потомок ведет разговор с клиентом и за- вершается после выхода из функции read. Процесс-сервер возвраща- ется к началу цикла и ждет поступления следующего запроса на подключение. На Рисунке 11.21 показан пример процесса-клиента, ведущего общение с сервером. Клиент создает гнездо в том же домене, что и сервер, и посылает запрос на подключение к гнезду с именем sockname. В результате подключения 358 +------------------------------------------------------------+ | #include | | #include | | | | main() | | { | | int sd,ns; | | char buf[256]; | | struct sockaddr sockaddr; | | int fromlen; | | | | sd = socket(AF_UNIX,SOCK_STREAM,0); | | | | /* имя гнезда - не может включать пустой символ */ | | bind(sd,"sockname",sizeof("sockname") - 1); | | listen(sd,1); | | | | for (;;) | | { | | | | ns = accept(sd,&sockaddr,&fromlen); | | if (fork() == 0) | | { | | /* потомок */ | | close(sd); | | read(ns,buf,sizeof(buf)); | | printf("сервер читает '%s'\n",buf); | | exit(); | | } | | close(ns); | | } | | } | +------------------------------------------------------------+ Рисунок 11.20. Процесс-сервер в домене "UNIX system" +------------------------------------------------------------+ | #include | | #include | | | | main() | | { | | int sd,ns; | | char buf[256]; | | struct sockaddr sockaddr; | | int fromlen; | | | | sd = socket(AF_UNIX,SOCK_STREAM,0); | | | | /* имя в запросе на подключение не может включать | | /* пустой символ */ | | if (connect(sd,"sockname",sizeof("sockname") - 1) == -1)| | exit(); | | | | write(sd,"hi guy",6); | | } | +------------------------------------------------------------+ Рисунок 11.21. Процесс-клиент в домене "UNIX system" 359 процесс-клиент получает виртуальный канал связи с сервером. В рассматривае- мом примере клиент передает одно сообщение и завершается. Если сервер обслуживает процессы в сети, указание о том, что гнездо при- надлежит домену "Internet", можно сделать следующим образом: socket(AF_INET,SOCK_STREAM,0); и связаться с сетевым адресом, полученным от сервера. В системе BSD имеются библиотечные функции, выполняющие эти действия. Второй параметр вызываемой клиентом функции connect содержит адресную информацию, необходимую для иден- тификации машины в сети (или адреса маршрутов посылки сообщений через проме- жуточные машины), а также дополнительную информацию, идентифицирующую прием- ное гнездо машины-адресата. Если серверу нужно одновременно следить за сос- тоянием сети и выполнением локальных процессов, он использует два гнезда и с помощью функции select определяет, с каким клиентом устанавливается связь в данный момент. 11.5 ВЫВОДЫ Мы рассмотрели несколько форм взаимодействия процессов. Первой формой, положившей начало обсуждению, явилась трассировка процессов - взаимодействие двух процессов, выступающее в качестве полезного средства отладки программ. При всех своих преимуществах трассировка процессов с помощью функции ptrace все же достаточно дорогостоящее и примитивное мероприятие, поскольку за один сеанс функция способна передать строго ограниченный объем данных, требуется большое количество переключений контекста, взаимодействие ограничивается только формой отношений родитель-потомок, и наконец, сама трассировка произ- водится только по обоюдному согласию участвующих в ней процессов. В версии V системы UNIX имеется пакет взаимодействия процессов (IPC), включающий в себя механизмы обмена сообщениями, работы с семафорами и разделения памяти. К со- жалению, все эти механизмы имеют узкоспециальное назначение, не имеют хоро- шей стыковки с другими элементами операционной системы и не действуют в се- ти. Тем не менее, они используются во многих приложениях и по сравнению с другими схемами отличаются более высокой эффективностью. Система UNIX поддерживает широкий спектр вычислительных сетей. Традици- онные методы согласования протоколов в сильной степени полагаются на помощь системной функции ioctl, однако в разных типах сетей они реализуются по-раз- ному. В системе BSD имеются системные функции для работы с гнездами, поддер- живающие более универсальную структуру сетевого взаимодействия. В будущем в версию V предполагается включить описанный в главе 10 потоковый механизм, повышающий согласованность работы в сети. 11.6 УПРАЖНЕНИЯ 1. Что произойдет в том случае, если в программе debug будет отсутствовать вызов функции wait (Рисунок 11.3) ? (Намек: возможны два исхода.) 2. С помощью функции ptrace отладчик считывает данные из пространства трассируемого процесса по одному слову за одну операцию. Какие измене- ния следует произвести в ядре операционной системы для того, чтобы уве- личить количество считываемых слов ? Какие изменения при этом необходи- мо сделать в самой функции ptrace ? 3. Расширьте область действия функции ptrace так, чтобы в качестве пара- метра pid можно было указывать идентификатор процесса, не являющегося потомком текущего процесса. Подумайте над вопросами, связанными с защи- той информации: При каких обстоятельствах процессу может быть позволено 360 читать данные из адресного пространства другого, произвольного процесса ? При каких обстоятельствах разрешается вести запись в адресное прост- ранство другого процесса ? 4. Организуйте из функций работы с сообщениями библиотеку пользовательско- го уровня с использованием обычных файлов, поименованных каналов и эле- ментов блокировки. Создавая очередь сообщений, откройте управляющий файл для записи в него информации о состоянии очереди; защитите файл с помощью средств захвата файлов и других удобных для вас механизмов. По- сылая сообщение данного типа, создавайте поименованный канал для всех сообщений этого типа, если такого канала еще не было, и передавайте со- общение через него (с подсчетом переданных байт). Управляющий файл дол- жен соотносить тип сообщения с именем поименованного канала. При чтении сообщений управляющий файл направляет процесс к соответствующему поиме- нованному каналу. Сравните эту схему с механизмом, описанным в настоя- щей главе, по эффективности, сложности реализации и функциональным воз- можностям. 5. Какие действия пытается выполнить программа, представленная на Рисунке 11.22 ? *6. Напишите программу, которая подключала бы область разделяемой памяти слишком близко к вершине стека задачи и позволяла бы стеку при увеличе- нии пересекать границу разделяемой области. В какой момент произойдет фатальная ошибка памяти ? 7. Используйте в программе, представленной на Рисунке 11.14, флаг IPC_NOWAIT, реализуя условный тип семафора. Продемонстрируйте, как за счет этого можно избежать возникновения взаимных блокировок. 8. Покажите, как операции над семафорами типа P и V реализуются при работе с поименованными каналами. Как бы вы реализовали операцию P условного типа ? 9. Составьте программы захвата ресурсов, использующие (а) поименованные каналы, (б) системные функции creat и unlink, (в) функции обмена сооб- щениями. Проведите сравнительный анализ их эффективности. 10. На практических примерах работы с поименованными каналами сравните эф- фективность использования функций обмена сообщениями, с одной стороны, с функциями read и write, с другой. 11. Сравните на конкретных программах скорость передачи данных при работе с разделяемой памятью и при использовании механизма обмена сообщениями. Программы, использующие разделяемую память, для синхронизации заверше- ния операций чтения-записи должны опираться на семафоры. +------------------------------------------------------------+ | #include | | #include | | #include | | #define ALLTYPES 0 | | | | main() | | { | | struct msgform | | { | | long mtype; | | char mtext[1024]; | | } msg; | | register unsigned int id; | | | | for (id = 0; ; id++) | | while (msgrcv(id,&msg,1024,ALLTYPES,IPC_NOWAIT) > 0)| | ; | | } | +------------------------------------------------------------+ 361