Стивенс Уильям Ричард
Шрифт:
В табл. 1.2 сведены соглашения об именовании для различных видов IPC.
Таблица 1.2. Пространства имен для различных типов IPC
| Тип IPC | Пространство имен для создания или открытия | Идентификатор после открытия | Posix.1 1996 | Unix 98 |
|---|---|---|---|---|
| Канал | (Без имени) | Дескриптор | • | • |
| FIFO | Имя файла (pathname) | Дескриптор | • | • |
| Взаимное исключение Posix | (Без имени) | Указатель типа pthread_mutex_t | • | • |
| Условная переменная Posix | (Без имени) | Указатель типа pthread_cond_t | • | • |
| Блокировка чтения-записи Posix | (Без имени) | Указатель типа pthread_rwlock_t | • | |
| Блокировка записей fcntl | Имя файла | Дескриптор | • | • |
| Разделяемая память Posix | Posix-имя IPC | Дескриптор | • | • |
| Очередь сообщений System V | Ключ key_t | Идентификатор IPC System V | • | |
| Семафор System V | Ключ key_t | Идентификатор IPC System V | • | |
| Разделяемая память System V | Ключ key_t | Идентификатор IPC System V | • | |
| Двери (doors) | Имя файла | Дескриптор | ||
| Удаленный вызов процедур (RPC) Sun | Программа/версия | Дескриптор (handle) RPC | ||
| Сокет TCP | IP-адрес и порт TCP | Дескриптор | .1g | • |
| Сокет UDP | IP-адрес и порт TCP | Дескриптор | .1g | • |
| Доменный сокет Unix (domain socket) | Полное имя файла | Дескриптор | .1g | • |
Здесь также указано, какие формы IPC содержатся в стандарте Posix.1 1996 года и какие были включены в стандарт Unix 98. Об обоих этих стандартах более подробно рассказано в разделе 1.7. Для сравнения мы включили в эту таблицу три типа сокетов, которые подробно описаны в [24]. Обратите внимание, что интерфейс сокетов (Application Program Interface — API) стандартизируется рабочей группой Posix.1g и должен в будущем стать частью стандарта Posix.1.
Хотя стандарт Posix. 1 и дает возможность использования семафоров, их поддержка не является обязательной для производителей. В табл. 1.3 сведены функции, описанные в стандартах Posix.1 и Unix 98. Каждая функция может быть обязательной (mandatory), неопределенной (not defined) или необязательной (дополнительной — optional). Для необязательных функций мы указываем имя константы (например, _POSIX_THREADS), которая будет определена (обычно в заголовочном файле <unistd.h>), если эта функция поддерживается. Обратите внимание, что Unix 98 содержит в себе Posix.1 в качестве подмножества.
Таблица 1.3. Доступность различных форм IPC
| Тип IPC | Posix.1 1996 | Unix 98 |
|---|---|---|
| Программный канал | Обязателен | Обязателен |
| FIFO | Обязателен | Обязателен |
| Взаимное исключение Posix | _POSIX_THREADS | Обязателен |
| Условная переменная Posix | _POSIX_THREADS | Обязателен |
| Взаимные исключения и условные переменные между процессами | _POSIX_THREADS_PROCESS_SHARED | Обязателен |
| Блокировка чтения-записи Posix | (He определен) | Обязателен |
| Блокировка записей fcntl | Обязателен | Обязателен |
| Очередь сообщений Posix | _POSIX_MESSAGE_PASSING | _XOPEN_REALTIME |
| Семафоры Posix | _POSIX_SEMAPHORES_ | _XOPEN_REALTIME |
| Память с общим доступом Posix | _POSIX_SHARED_MEMORY_OBJECTS | _XOPEN_REALTIME |
| Очередь сообщений System V | (He определен) | Обязателен |
| Семафор System V | (He определен) | Обязателен |
| Память с общим доступом System V | (He определен) | Обязателен |
| Двери (doors) | (He определен) | (Не определен) |
| Удаленный вызов процедур Sun | (He определен) | (Не определен) |
| Отображение памяти mmap | _POSIX_MAPPED_FILES или POSIX_SHARED_MEMORY_OBJECTS | Обязателен |
| Сигналы реального времени (realtime signals) | _POSIX_REALTIME_SIGNALS | _XOPEN_REALTIME |
1.5. Действие команд fork, exec и exit на объекты IPC
Нам нужно достичь понимания действия функций fork, exec и _exit на различные формы IPC, которые мы обсуждаем (последняя из перечисленных функций вызывается функцией exit). Информация по этому вопросу сведена в табл. 1.4.
Большинство функций описаны далее в тексте книги, но здесь нужно сделать несколько замечаний. Во-первых, вызов fork из многопоточного процесса (multithreaded process) приводит к беспорядку в безымянных переменных синхронизации (взаимных исключениях, условных переменных, блокировках и семафорах, хранящихся в памяти). Раздел 6.1 книги [3] содержит необходимые детали. Мы просто отметим в добавление к таблице, что если эти переменные хранятся в памяти с общим доступом и создаются с атрибутом общего доступа для процессов, они будут доступны любому процессу, который может обращаться к этой области памяти. Во-вторых, три формы IPC System V не могут быть открыты или закрыты. Из листинга 6.6 и упражнений 11.1 и 14.1 видно, что все, что нужно знать, чтобы получить доступ к этим трем формам IPC, — это идентификатор. Поэтому они доступны всем процессам, которым известен этот идентификатор, хотя для семафоров и памяти с общим доступом требуется некая особая обработка.
Таблица 1.4. Действие fork, exec и _exit на IPC
| Тип IPC | fork | exec | _exit |
|---|---|---|---|
| Неименованные и именованные каналы | Порожденный процесс получает копии всех дескрипторов родительского процесса | Все открытые дескрипторы остаются открытыми, если для них не установлен бит FD_CLOEXEC | Все открытые дескрипторы закрываются, данные из программного канала и FIFO удаляются после последнего закрытия |
| Очереди сообщений Posix | Порожденный процесс получает копии всех открытых родительских процессов | Все открытые дескрипторы очередей сообщений закрываются | Все открытые дескрипторы очередей сообщений закрываются |
| Очереди сообщений System V | Не действует | Не действует | Не действует |
| Взаимные исключения и условные переменные Posix | Общий доступ, если используется разделяемая память с атрибутом разделения между процессами | Исчезает, если не хранится в разделяемой памяти, которая остается открытой и имеет атрибут разделения | Исчезает, если не находится в разделяемой памяти, которая остается открытой и имеет атрибут разделения |
| Блокировки чтения-записи Posix | Общий доступ, если используется память с общим доступом и атрибутом разделения между процессами | Исчезает, если не хранится в разделяемой памяти, которая остается открытой и имеет атрибут разделения | Исчезает, если не хранится в разделяемой памяти, которая остается открытой и имеет атрибут разделения |
| Семафоры Posix, хранящиеся в памяти | Общий доступ, если используется память с общим доступом и атрибутом разделения между процессами | Исчезает, если не хранится в разделяемой памяти, которая остается открытой и имеет атрибут разделения | Исчезает, если не хранится в разделяемой памяти, которая остается открытой и имеет атрибут разделения |
| Именованные семафоры Posix | Все открытые в родительском процессе остаются открытыми в порожденном | Все открытые закрываются | Все открытые закрываются |
| Семафоры System V | Все значения semadj в порожденном процессе устанавливаются в 0 | Все значения semadj передаются новой программе | Все значения semadj добавляются к значению соответствующего семафора |
| Блокировка записей fcntl | Блокировки в родительском процессе не наследуются порожденным процессом | Блокировки не изменяются до тех пор, пока не закроется дескриптор | Все несброшенные блокировки, установленные процессом, снимаются |
| Отображение памяти | Отображения памяти родительского процесса сохраняются в порожденном | Отображения памяти сбрасываются (unmap) | Отображения памяти сбрасываются |
| Разделяемая память Posix | Отображения памяти родительского процесса сохраняются в порожденном | Отображения памяти сбрасываются | Отображения памяти сбрасываются |
| Разделяемая память System V | Присоединенные сегменты разделяемой памяти остаются присоединенными в порожденном процессе | Присоединенные сегменты разделяемой памяти отсоединяются | Присоединенные сегменты разделяемой памяти отсоединяются |
| Двери (doors) | Порожденный процесс получает копии всех открытых дескрипторов родительского процесса, но только родительский процесс является сервером при активизации дверей через дескрипторы | Все дескрипторы дверей должны быть закрыты, потому что они создаются с установленным битом FD_CLOEXEC | Все открытые дескрипторы закрываются |
1.6. Обработка ошибок: функции-обертки
В любой реальной программе при любом вызове требуется проверка возвращаемого значения на наличие ошибки. Поскольку обычно работа программ при возникновении ошибок завершается, мы можем сократить объем текста, определив функции-обертки (wrapper functions), которые осуществляют собственно вызов функции, проверяют возвращаемое значение и завершают работу при возникновении ошибок. В соответствии с соглашениями имена функций-оберток совпадают с именами самих функций, за исключением первой буквы, которая делается заглавной, например