Операционная система UNIX - страница 117
>
Разделяемая память
Интенсивный обмен данными между процессами с использованием рассмотренных механизмов межпроцессного взаимодействия (каналы, FIFO, очереди сообщений) может вызвать падение производительности системы. Это, в первую очередь, связано с тем, что данные, передаваемые с помощью этих объектов, копируются из буфера передающего процесса в буфер ядра и затем в буфер принимающего процесса. Механизм разделяемой памяти позволяет избавиться от накладных расходов передачи данных через ядро, предоставляя двум или более процессам возможность непосредственного получения доступа к одной области памяти для обмена данными.
Безусловно, процессы должны предварительно "договориться" о правилах использования разделяемой памяти. Например, пока один из процессов производит запись данных в разделяемую память, другие процессы должны воздержаться от работы с ней. К счастью, задача кооперативного использования разделяемой памяти, заключающаяся в синхронизации выполнения процессов, легко решается с помощью семафоров.
Примерный сценарий работы с разделяемой памятью выглядит следующим образом:
1. Сервер получает доступ к разделяемой памяти, используя семафор.
2. Сервер производит запись данных в разделяемую память.
3. После завершения записи сервер освобождает разделяемую память с помощью семафора.
4. Клиент получает доступ к разделяемой памяти, запирая ресурс с помощью семафора.
5. Клиент производит чтение данных из разделяемой памяти и освобождает ее, используя семафор.
Для каждой области разделяемой памяти, ядро поддерживает структуру данных >shmid_ds
, основными полями которой являются:
>struct ipc_perm shm_perm | Права доступа, владельца и создателя области (см. описание >ipc_perm выше) |
>int shm_segsz | Размер выделяемой памяти |
>ushort shm_nattch | Число процессов, использующих разделяемую память |
>time_t shm_atime | Время последнего присоединения к разделяемой памяти |
>time_t shm_dtime | Время последнего отключения от разделяемой памяти |
>time_t shm_ctime | Время последнего изменения |
Для создания или для доступа к уже существующей разделяемой памяти используется системный вызов shmget(2):
>#include
>#include
>#include
>int shmget(key_t key, int size, int shmflag);
Функция возвращает дескриптор разделяемой памяти в случае успеха, и -1 в случае неудачи. Аргумент >size
определяет размер создаваемой области памяти в байтах. Значения аргумента >shmflag
задают права доступа к объекту и специальные флаги >IPC_CREAT
и >IPC_EXCL
. Заметим, что вызов shmget(2) лишь создает или обеспечивает доступ к разделяемой памяти, но не позволяет работать с ней. Для работы с разделяемой памятью (чтение и запись) необходимо сначала присоединить (attach) область вызовом shmat(2):
>#include
>#include
>#include
>char *shmat(int shmid, char *shmaddr, int shmflag);
Вызов shmat(2) возвращает адрес начала области в адресном пространстве процесса размером >size
, заданным предшествующем вызовом shmget(2). В этом адресном пространстве взаимодействующие процессы могут размещать требуемые структуры данных для обмена информацией. Правила получения этого адреса следующие:
1. Если аргумент >shmaddr
нулевой, то система самостоятельно выбирает адрес.
2. Если аргумент >shmaddr
отличен от нуля, значение возвращаемого адреса зависит от наличия флажка >SHM_RND
в аргументе >shmflag
:
• Если флажок >SHM_RND
не установлен, система присоединяет разделяемую память к указанному >shmaddr
адресу.
• Если флажок >SHM_RND
установлен, система присоединяет разделяемую память к адресу, полученному округлением в меньшую сторону >shmaddr
до некоторой определенной величины >SHMLBA
.
По умолчанию разделяемая память присоединяется с правами на чтение и запись. Эти права можно изменить, указав флажок >SHM_RDONLY
в аргументе >shmflag
.
Таким образом, несколько процессов могут отображать область разделяемой памяти в различные участки собственного виртуального адресного пространства, как это показано на рис. 3.20.
Рис. 3.20. Совместное использование разделяемой памяти
Окончив работу с разделяемой памятью, процесс отключает (detach) область вызовом