- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания UNIX: взаимодействие процессов - Уильям Стивенс
Шрифт:
Интервал:
Закладка:
. . . процесс 17977 продолжает работу
pid 17977: 32
pid 17976: 33 ядро переключается междупроцессами
. . . процесс 17976 продолжает работу
pid 17976: 707
pid 17978: 708 ядро переключается между процессами
. . . процесс 17978 продолжает работу
pid 17978: 852
pid 17977: 853 ядро переключается между процессами
. . . и т.д.
pid 17977: 29997
pid 17977: 29999 последнее выводимое значение. Оно оказывается правильным.
13.6. Отправка сообщений на сервер
Изменим наше решение задачи производителей и потребителей следующим образом. Сначала запускается сервер, создающий объект разделяемой памяти, в который клиенты записывают свои сообщения. Сервер просто выводит содержимое этих сообщений, хотя задачу можно и обобщить таким образом, чтобы он выполнял действия, аналогичные демону syslog, который описан в главе 13 [24]. Мы называем группу отправляющих сообщения процессов клиентами, потому что по отношению к нашему серверу они ими и являются, однако эти клиенты могут являться серверами по отношению к другим приложениям. Например, сервер Telnet является клиентом демона syslog, когда отправляет ему сообщения для занесения их в системный журнал.
Вместо передачи сообщений одним из описанных ранее методов (часть 2) будем хранить сообщения в разделяемой памяти. Это, разумеется, потребует какой-либо формы синхронизации действий клиентов, помещающих сообщения, и сервера, читающего их. На рис. 13.2 приведена схема приложения в целом.
Рис. 13.2. Несколько клиентов отправляют сообщения серверу через разделяемую память
Перед нами взаимодействие нескольких производителей (клиентов) и одного потребителя (сервер). Разделяемая память отображается в адресное пространство сервера и каждого из клиентов.
В листинге 13.8 приведен текст заголовочного файла cliserv2.h, в котором определена структура объекта, хранимого в разделяемой памяти.
Листинг 13.8. Заголовочный файл, определяющий содержимое разделяемой памяти//pxshm/cliserv2.h
1 #include "unpipc.h"
2 #define MESGSIZE 256 /* максимальный размер сообщения в байтах, включая завершающий ноль */
3 #define NMESG 16 /* максимальное количество сообщений */
4 struct shmstruct { /* структура, хранящаяся в разделяемой памяти */
5 sem_t mutex; /* три семафора Posix, размещаемые в памяти */
6 sem_t nempty;
7 sem_t nstored;
8 int nput; /* индекс для следующего сообщения */
9 long noverflow; /* количество переполнений */
10 sem_t noverflowmutex; /* взаимное исключение для счетчика переполнений */
11 long msgoff[NMESG]; /* сдвиг для каждого из сообщений */
12 char msgdata[NMESG * MESGSIZE]; /* сами сообщения */
13 };
Основные семафоры и переменные5-8 Три семафора Posix, размещаемых в памяти, используются для того же, для чего семафоры использовались в задаче производителей и потребителей в разделе 10.6. Их имена mutex, nempty, nstored. Переменная nput хранит индекс следующего помещаемого сообщения. Поскольку одновременно работают несколько производителей, эта переменная защищена взаимным исключением и хранится в разделяемой памяти вместе со всеми остальными.
Счетчик переполнений9-10 Существует вероятность того, что клиент не сможет отправить сообщение из-за отсутствия свободного места для него. Если программа-клиент представляет собой сервер для других приложений (например, сервер FTP или HTTP), она не должна блокироваться в ожидании освобождения места для сообщения. Поэтому программа-клиент будет написана таким образом, чтобы она не блокировалась, но увеличивала счетчик переполнений (noverflow). Поскольку этот счетчик также является общим для всех процессов, он также должен быть защищен взаимным исключением, чтобы его значение не было повреждено.
Сдвиги сообщений и их содержимое11-12 Массив msgoff содержит сдвиги сообщений в массиве msgdata, в котором сообщения хранятся подряд. Таким образом, сдвиг первого сообщения msgoff[0] = 0, msgoff [1] = 256 (значение MESGSIZE), msgoff [2] = 512 и т. д.
Нужно понимать, что при работе с разделяемой памятью использовать сдвиг в таких случаях необходимо, поскольку объект разделяемой памяти может быть отображен в разные области адресного пространства процесса (может начинаться с разных физических адресов). Возвращаемое mmap значение для каждого процесса может быть индивидуальным. Поэтому при работе с объектами разделяемой памяти нельзя использовать указатели, содержащие реальные адреса переменных в этом объекте.
В листинге 13.9 приведен текст программы-сервера, которая ожидает помещения сообщений в разделяемую память, а затем выводит их.
Листинг 13.9. Сервер, считывающий сообщения из разделяемой памяти//pxshm/server2.c
1 #include "cliserv2.h"
2 int
3 main(int argc, char **argv)
4 {
5 int fd, index, lastnoverflow, temp;
6 long offset;
7 struct shmstruct *ptr;
8 if (argc != 2)
9 err_quit("usage: server2 <name>");
10 /* создание объекта разделяемой памяти, установка размера, отображение в память, закрытие дескриптора */
11 shm_unlink(Px_ipc_name(argv[1])); /* ошибка игнорируется */
12 fd = Shm_open(Px_ipc_name(argv[1]), O_RDWR | O_CREAT | O_EXCL, FILE_MODE);
13 ptr = Mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE,
14 MAP_SHARED, fd, 0);
15 Ftruncate(fd, sizeof(struct shmstruct));
16 Close(fd);
17 /* инициализация массива сдвигов */
18 for (index = 0; index < NMESG; index++)
19 ptr->msgoff[index] = index * MESGSIZE;
20 /* инициализация семафоров в разделяемой памяти */
21 Sem_init(&ptr->mutex, 1, 1);
22 Sem_init(&ptr->nempty, 1, NMESG);
23 Sem_init(&ptr->nstored, 1, 0);
24 Sem_init(&ptr->noverflowmutex, 1, 1);
25 /* программа-потребитель */
26 index = 0;
27 lastnoverflow = 0;
28 for (;;) {
29 Sem_wait(&ptr->nstored);
30 Sem_wait(&ptr->mutex);
31 offset = ptr->msgoff[index];
32 printf("index = %d: %sn", index, &ptr->msgdata[offset]);
33 if (++index >= NMESG)
34 index =0; /* циклический буфер */
35 Sem_post(&ptr->mutex);
36 Sem_post(&ptr->nempty);
37 Sem_wait(&ptr->noverflowmutex);
38 temp = ptr->noverflow; /* не выводим, пока не снимем блокировку */
39 Sem_post(&ptr->noverflowmutex);
40 if (temp != lastnoverflow) {
41 printf("noverflow = %dn", temp);
42 lastnoverflow = temp;
43 }
44 }
45 exit(0);
46 }
Создание объекта разделяемой памяти10-16 Сначала делается вызов shm_unlink, чтобы удалить объект с тем же именем, который мог остаться после другого приложения. Затем объект разделяемой памяти создается вызовом shm_open и отображается в адресное пространство процесса вызовом mmap, после чего дескриптор объекта закрывается.
Инициализация массива сдвигов17-19 Массив сдвигов инициализируется сдвигами сообщений.
Инициализация семафоров20-24 Инициализируются четыре семафора, размещаемые в объекте разделяемой памяти. Второй аргумент sem_init всегда делается ненулевым, поскольку семафоры будут использоваться совместно несколькими процессами.
Ожидание сообщения, вывод его содержимого25-36 Первая половина цикла for написана по стандартному алгоритму потребителя: ожидание изменения семафора nstored, установка блокировки для семафора mutex, обработка данных, увеличение значения семафора nempty.
Обработка переполнений37-43 При каждом проходе цикла мы проверяем наличие возникших переполнений. Сравнивается текущее значение noverflows с предыдущим. Если значение изменилось, оно выводится на экран и сохраняется. Обратите внимание, что значение считывается с заблокированным взаимным исключением noverflowmutex, но блокировка снимается перед сравнением и выводом значения. Идея в том, что нужно всегда следовать общему правилу минимизации количества операций, выполняемых с заблокированным взаимным исключением. В листинге 13.10 приведен текст программы-клиента.
Листинг 13.10. Клиент, помещающий сообщения в разделяемую память//pxshm/client2.c
1 #include "cliserv2.h"
2 int
3 main(int argc, char **argv)
4 {
5 int fd, i, nloop, nusec;
6 pid_t pid;
7 char mesg[MESGSIZE];
8 long offset;
9 struct shmstruct *ptr;
10 if (argc != 4)