- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания UNIX: взаимодействие процессов - Уильям Стивенс
Шрифт:
Интервал:
Закладка:
1. Дескриптор, возвращаемый door_create, считается первой ссылкой на эту дверь. Вообще говоря, причина, по которой специальный вызов происходит при изменении количества дескрипторов с 2 на 1, а не с 1 на 0, заключается в том, что первый дескриптор обычно не закрывается сервером до завершения работы.
2. Полное имя, связанное с дверью в файловой системе, также считается ссылкой на дверь. Ее можно удалить вызовом функции fdetach, или запустив программу fdetach, или удалив полное имя из файловой системы (функцией unlink или командой rm).
3. Дескриптор, возвращаемый клиенту функцией open, считается открытой ссылкой до тех пор, пока не будет закрыт либо явным вызовом close, либо неявно, при завершении клиента. Во всех примерах этой главы дескриптор закрывается неявно.
Первый пример показывает, что если сервер закрывает свой дескриптор после вызова fattach, немедленно происходит специальный вызов процедуры сервера. В листинге 15.13 приведен текст процедуры сервера и функции main.
Листинг 15.13. Процедура сервера, обрабатывающая специальный вызов//doors/serverunref1.c
1 #include "unpipc.h"
2 void
3 servproc(void *cookie, char *dataptr, size_t datasize,
4 door_desc_t *descptr, size_t ndesc)
5 {
6 long arg, result;
7 if (dataptr == DOOR_UNREF_DATA) {
8 printf("door unreferencedn");
9 Door_return(NULL, 0, NULL, 0);
10 }
11 arg = *((long*)dataptr);
12 printf("thread id %ld, arg = %ldn", pr_thread_id(NULL), arg);
13 sleep(6);
14 result = arg * arg;
15 Door_return((char *)&result, sizeof(result), NULL, 0);
16 }
17 int
18 main(int argc, char **argv)
19 {
20 int fd;
21 if (argc != 2)
22 err_quit("usage: server1 <server-pathname>");
23 /* создание дескриптора и связывание с файлом */
24 fd = Door_create(servproc, NULL, DOOR_UNREF);
25 unlink(argv[1]);
26 Close(Open(argv[1], O_CREAT | O_RDWR, FILE_MODE));
27 Fattach(fd, argv[1]);
28 Close(fd);
29 /* процедура servproc() обрабатывает все запросы клиентов */
30 for(;;)
31 pause();
32 }
7-10 Процедура сервера распознает специальный вызов и выводит сообщение об этом. Возврат из специального вызова происходит путем вызова door_return с двумя нулевыми указателями и нулевыми значениями размеров.
28 Теперь мы закрываем дескриптор двери после выполнения fattach. Этот дескриптор может быть нужен серверу только для вызовов door_bind, doo_info и door_revoke.
Запустив сервер, мы увидим, что немедленно произойдет специальный вызов:
solaris % serverunref1 /tmp/door1
door unreferenced
Если мы проследим за значением счетчика открытых дескрипторов, мы увидим, что он становится равен 1 после возврата из door_create и 2 после возврата из fattach. Вызов close уменьшает количество открытых дескрипторов с двух до одного, что приводит к специальному вызову процедуры. Единственная оставшаяся ссылка при этом представляет собой имя в файловой системе, а этого клиенту достаточно, чтобы обратиться к двери. Поэтому клиент продолжает работать правильно:
solaris % clientunref1 /tmp/door1 11
result: 121
solaris % clientunref1 /tmp/door1 22
result: 484
Более того, дальнейших специальных вызовов серверной процедуры не происходит. Для каждой двери осуществляется только один специальный вызов.
Теперь изменим нашу программу-сервер обратно, убрав вызов close для дескриптора двери. Процедура сервера и функция main приведены в листинге 15.14.
Листинг 15.14. Сервер, не закрывающий дескриптор двери//doors/serverunref2.c
1 #include "unpipc.h"
2 void
3 servproc(void *cookie. char *dataptr, size_t datasize,
4 door_desc_t *descptr, size_t ndesc)
5 {
6 long arg, result;
7 if (dataptr == DOOR_UNREF_DATA) {
8 printf("door unreferencedn");
9 Door_return(NULL, 0, NULL, 0);
10 }
11 arg = *((long *)dataptr);
12 printf("thread id %ld, arg = %ldn", pr_thread_id(NULL), arg);
13 sleep(6);
14 result = arg * arg;
15 printf("thread id %ld returningn", pr_thread_id(NULL));
16 Door_return((char *)&result, sizeof(result), NULL, 0);
17 }
18 int
19 main(int argc, char **argv)
20 {
21 int fd;
23 if (argc != 2)
24 err_quit("usage: server1 <server-pathname>");
25 /* создание двери, дескриптора и подключение к файлу */
26 fd = Door_create(servproc, NULL, DOOR_UNREF);
27 unlink(argv[1]);
28 Close(Open(argv[1], O_CREAT | O_RDWR, FILE_MODE));
29 Fattach(fd, argv[1]);
30 /* servproc() обрабатывает все запросы клиентов */
31 for(;;)
32 pause();
33 }
Мы оставляем 6-секундную паузу и выводим сообщение о возврате из процедуры сервера. Запустим сервер в одном окне, а из другого проверим существование имени файла двери в файловой системе и удалим его с помощью rm:
solaris % ls –l /tmp/door2
Drw-r--r-- 1 rstevens other1 0 Apr 16 08:58 /tmp/door2
solaris % rm /tmp/door2
После удаления имени файла происходит специальный вызов процедуры сервера:
solaris % serverunref2 /trap/door2
door unreferenced после удаления файла из файловой системы
Если мы проследим за количеством ссылок на эту дверь, то увидим следующее: одна ссылка появляется после вызова door_create, вторая — после fattach. После удаления файла с помощью rm количество ссылок снова уменьшается до единицы, что приводит к специальному вызову процедуры.
В последнем примере использования этого атрибута мы снова удалим имя из файловой системы. Но на этот раз мы сначала запустим три экземпляра программы-клиента. Специальный вызов процедуры произойдет только после завершения последнего клиента, потому что каждый экземпляр клиента увеличивает количество ссылок на дверь. Используем сервер из листинга 15.14 и клиент из листинга 15.2.
solaris % clientunref2 /tmp/door2 44 & clientunref2 /tmp/door2 55 & clientunref2/tmp/door2 55 &
[2] 13552
[3] 13553
[4] 13554
solaris % rm /tmp/door2 клиенты все еще выполняются
solaris % result: 1936
result: 3025
result: 4356
Сервер при этом выведет вот что:
solaris % serverunref2 /tmp/door2
thread id 4, arg = 44
thread id 5, arg = 55
thread id 6, arg = 66
thread id 4 returning
thread id 5 returning
thread id 6 returning
door unreferenced
Проследим за значением счетчика открытых ссылок для этой двери. Он становится равным 1 после вызова door_create, 2 после вызова fattach. Когда три клиента вызывают open, счетчик увеличивается с 2 до 5. После удаления имени файла счетчик уменьшается до 4. После завершения работы трех клиентов счетчик уменьшается с 4 до 1 (последовательно), и последнее его изменение с 2 до 1 приводит к специальному вызову процедуры.
Этими примерами мы показали, что хотя описание атрибута DOOR_UNREF выглядит просто («специальный вызов происходит при изменении счетчика ссылок с 2 до 1»), мы должны понимать принципы работы этого счетчика, чтобы им пользоваться.
15.8. Передача дескрипторов
Когда мы говорим о передаче открытого дескриптора от одного процесса другому, обычно подразумевается одно из двух:
■ наследование всех открытых дескрипторов родительского процесса дочерним после вызова fork;
■ сохранение открытых дескрипторов при вызове exec.
В первом случае процесс открывает дескриптор, вызывает fork, а затем родительский процесс закрывает дескрипторы, предоставляя дочернему возможность работать с ними. При этом открытый дескриптор передается от родительского процесса дочернему.
В современных версиях Unix возможности передачи дескрипторов существенно расширены, и теперь имеется возможность передавать открытый дескриптор от одного процесса другому вне зависимости от их родства. Двери являются одним из существующих интерфейсов для передачи дескрипторов от клиента серверу и от сервера клиенту.
ПРИМЕЧАНИЕ
Передача дескрипторов через доменные сокеты Unix была описана в разделе 14.7 [24]. В ядрах Berkeley и производных от них дескрипторы передаются именно через такие сокеты. Все подробности описаны в главе 18 [23]. В ядрах SVR4 используются другие методы передачи дескрипторов, а именно команды I_SENDFD и I_RECVFD функции ioctl. Они описаны в разделе 15.5.1 [21]. Но процесс в SVR4 может воспользоваться и механизмом доменных сокетов Unix.
Нужно правильно понимать, что именно подразумевается под передачей дескриптора. На рис. 4.7 сервер открывал файл и копировал его целиком через нижний (на рисунке) канал. Если размер файла 1 Мбайт, через канал будет передан 1 Мбайт данных. Но если сервер передает клиенту дескриптор вместо самого файла, то через канал передается только дескриптор (который содержит небольшое количество информации ядра). Клиент может использовать этот дескриптор для считывания содержимого файла. Чтение файла при этом осуществляется именно клиентом, а сервер осуществляет только открытие файла.