- •Часть 4. Локальное взаимодействие процессов
- •Глава 16. Блокирование записей 89
- •12.2. Процессы, потоки и общий доступ к информации
- •12.3. Живучесть объектов ipc
- •12.4. Пространства имен
- •12.5. Действие команд fork, exec и exit на объекты ipc
- •12.6. Комментарии к примерам ipc
- •12.7. Выводы по главе 12
- •12.8. Упражнения по главе 12
- •Глава 13. Именованные и неименованные каналы
- •13.1. Введение
- •13.2. Приложение типа клиент-сервер
- •13.3. Программные каналы
- •13.4. Функции popen и pclose
- •13.5. Именованные каналы (fifo)
- •13.6. Некоторые свойства именованных и неименованных каналов
- •13.7. Один сервер, несколько клиентов
- •13.8. Последовательные и параллельные серверы
- •13.9. Ограничения программных каналов и fifo
- •13.10. Выводы по главе 13
- •13.11. Упражнения по главе 13
- •Глава 14. Программные потоки
- •14.1. Введение
- •14.2. Концепция потоков
- •14.3. Идентификация потоков
- •14.4. Создание потока
- •14.5. Завершение потока
- •Функции управления процессами и потоками
- •14.6. Установка атрибутов потока
- •14.7. Реентерабельность
- •Альтернативные версии функций, безопасные в многопоточной среде
- •14.8. Локальные данные потоков
- •14.9. Принудительное завершение потоков
- •Некоторые точки выхода, определенные стандартом Posix.1
- •14.10. Потоки и сигналы
- •14.11. Выводы по главе 14
- •14.12. Упражнения по главе 14 Глава 15. Средства синхронизации потоков
- •15.1. Введение
- •15.2. Взаимные исключения: установка и снятие блокировки
- •15.2.1. Схема производитель-потребитель
- •15.2.2. Блокирование и опрос
- •15.2.3. Предотвращение тупиковых ситуаций
- •15.3. Условные переменные
- •15.3.1. Ожидание и сигнализация
- •15.3.2. Исключение состояния гонок
- •15.4. Блокировки чтения-записи
- •15.5. Атрибуты средств синхронизации потоков
- •15.5.1. Атрибуты взаимных исключений
- •Поведение взаимных исключений различных типов
- •15.5.2. Атрибуты условных переменных
- •15.5.3. Атрибуты блокировок чтения-записи
- •15.6. Выводы по главе 15
- •15.7. Упражнения по главе 15
- •Глава 16. Блокирование записей
- •16.1. Введение
- •16.2. Блокирование записей и файлов
- •16.3. Блокирование записей с помощью fcntl по стандарту Posix
- •16.4. Рекомендательная блокировка
- •16.5. Обязательная блокировка
- •16.6. Приоритет чтения и записи Выводы по главе 16
- •Упражнения по главе 16 Глава 17. System V ipc
- •17.1. Введение
- •17.2. Ключи типа key_t и функция ftok
- •17.3. Структура ipc_perm
- •17.4. Создание и открытие каналов ipc
- •17.5. Разрешения ipc
- •17.6. Программы ipcs и ipcrm
- •17.7. Ограничения ядра
- •17.8. Выводы по главе 17
- •17.9. Упражнения по главе 17
- •Глава 18. Очереди сообщений System V
- •18.1. Введение
- •18.2. Функция msgget
- •18.3. Функция msgsnd
- •18.4. Функция msgrcv
- •18.5. Функция msgctl
- •18.6. Пример программы клиент-сервер
- •18.7. Мультиплексирование сообщений
- •18.7.1. Пример: одна очередь на приложение
- •18.7.2. Пример: одна очередь для каждого клиента
- •18.8. Ограничения, накладываемые на очереди сообщений
- •18.9. Выводы по главе 18
- •18.10. Упражнения по главе 18
- •Глава 19. Семафоры System V
- •19.1. Введение
- •19.2. Функция semget
- •19.3. Функция semop
- •19.4. Функция semctl
- •19. . Ограничения семафоров System V
- •19. . Выводы по главе 19
- •19. . Упражнения по главе 19 Глава 20. Введение в разделяемую память
- •20.1. Введение
- •20.2. Функции mmap, munmap и msync
- •20.3. Увеличение счетчика в отображаемом в память файле
- •20.4. Неименованное отображение в память
- •20.5. Обращение к объектам, отображенным в память
- •20.6. Выводы по главе 20
- •20.7. Упражнения по главе 20
- •Глава 21. Разделяемая память System V
- •21.1. Введение
- •21.2. Функция shmget
- •21.3. Функция shmat
- •21.4. Функция shmdt
- •21.5. Функция shmctl
- •21.6. Ограничения, накладываемые на разделяемую память
- •21.7. Выводы по главе 21
- •21.8. Упражнения по главе 21
21.3. Функция shmat
После создания или открытия сегмента разделяемой памяти вызовом shmgetего нужно подключить к адресному пространству процесса вызовомshmat:
#include <sys/shm.h>
void *shmat (int shmid, const void *shmaddr, int flag);
/* возвращает начальный адрес полученной области в случае успешного завершения, -1 – в случае ошибки */
Аргумент shmid– это идентификатор сегмента разделяемой памяти, возвращенныйshmget. Функцияshmatвозвращает адрес начала области разделяемой памяти в адресном пространстве вызвавшего процесса. Правила, по которым формируется этот адрес, таковы:
если аргумент shmaddrпредставляет собой нулевой указатель, система сама выбирает начальный адрес для вызвавшего процесса. Это рекомендуемый (и обеспечивающий наилучшую совместимость) метод;
если shmaddrотличен от нуля, возвращаемый адрес зависит от того, был ли указан флагSHM_RND(в аргументеflag).
По умолчанию сегмент подключается для чтения и записи, если процесс обладает соответствующими разрешениями. В аргументе flagможно указать константуSHM_RDONLY, которая позволит установить доступ только для чтения.
21.4. Функция shmdt
После завершения работы с сегментом разделяемой памяти его следует отключить вызовом shmdt:
#include <sys/shm.h>
int shmdt (const void *shmaddr);
/* возвращает 0 в случае успешного завершения, -1 – в случае ошибки */
При завершении работы процесса все сегменты, которые не были отключены им явно, отключаются автоматически.
Обратите внимание, что эта функция удаляет сегмент разделяемой памяти только в том случае, когда сегмент помечен для удаления и значение поля shm_nattchструктурыshmid_dsравно нулю. Пометка сегмента для удаления осуществляется функциейshmctlс командойIPC_RMID.
21.5. Функция shmctl
Функция shmctlпозволяет выполнять различные операции с сегментом разделяемой памяти:
#include <sys/shm.h>
int shmctl (int shmid, int cmd, struct shmid_ds *buff);
/* возвращает 0 в случае успешного завершения, -1 – в случае ошибки */
Команд (значений аргумента cmd) может быть три:
IPC_RMID– помечает сегмент разделяемой памяти с идентификаторомshmidдля удаления. Сегмент, помеченный для удаления, может быть удален функциейshmdtтолько тогда, когда к нему не будет подключен ни один процесс;
IPC_SET– установка значений полей структурыshmid_dsдля сегмента разделяемой памяти равными значениям соответствующих полей структуры, на которую указывает аргументbuff:shm_perm.uid,shm_perm.gid,shm_perm.mode. Значение поля shm_ctime устанавливается равным текущему системному времени;
IPC_STAT– возвращает вызывающему процессу (через аргументbuff) текущее значение структурыshmid_dsдля указанного сегмента разделяемой памяти.
Пример. В листинге 20.1 приведен пример простой программы, иллюстрирующей работу с разделяемой памятьюSystem V.
Листинг 20.1. Манипулирование сегментом разделяемой памяти указанного размера
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SVSHM_MODE (SHM_R | SHM_W | SHM_R>>3 | SHM_R>>6)
int main(int argc, char **argv)
{
int i, id, oflag;
unsigned char *ptr;
size_t length;
key_t shmkey;
struct shmid_ds buff;
oflag = SVSHM_MODE | IPC_CREAT;
while ((i = getopt(argc, argv, "e")) != -1)
{ /* получение опций командной строки */
switch (i)
{
case 'e':
oflag |= IPC_EXCL;
break;
}
}
if (optind != argc - 2)
{
fprintf(stderr, "Использование: shm [ -e ] <имя_файла>
<размер_сегмента>\n");
exit(1);
}
if ((shmkey = ftok(argv[optind], 0)) == -1)
{
fprintf(stderr, "Ошибка вызова функции ftok: %s\n", strerror(errno));
exit(1);
}
length = atoi(argv[optind + 1]);
if ((id = shmget(shmkey, length, oflag)) == -1)
{
fprintf(stderr, "Ошибка вызова функции shmget: %s\n", strerror(errno));
exit(1);
}
if ((ptr = shmat(id, NULL, 0)) == -1)
{
fprintf(stderr, "Ошибка вызова функции shmat: %s\n", strerror(errno));
exit(1);
}
if (shmctl(id, IPC_STAT, &buff) == -1)
{
fprintf(stderr, "Ошибка вызова функции shmctl(IPC_STAT): %s\n",
strerror(errno));
exit(1);
}
/* заполнение сегмента разделяемой памяти: ptr[0] = 0, ptr[1] = 1 и т. д. */
for (i = 0; i < buff.shm_segsz; i++)
ptr[i] = i % 256;
/* проверка значений ptr[0] = 0, ptr[1] = 1 и т. д. */
for (i = 0; i < buff.shm_segsz; i++)
if (ptr[i] != (i % 256))
fprintf(stderr, "ptr[%d] = %d\n", i, ptr[i]);
if (shmctl(id, IPC_RMID, NULL) == -1)
{
fprintf(stderr, "Ошибка вызова функции shmctl(IPC_RMID): %s\n",
strerror(errno));
exit(1);
}
if (shmdt(ptr) == -1)
{
fprintf(stderr, "Ошибка вызова функции shmdt: %s\n", strerror(errno));
exit(1);
}
exit(0);
}
