#include
#include
#include
char *shmat(int shmid, char *shmaddr, int shmflag);
Вызов size
, заданным предшествующем вызовом
1. Если аргумент shmaddr
нулевой, то система самостоятельно выбирает адрес.
2. Если аргумент shmaddr
отличен от нуля, значение возвращаемого адреса зависит от наличия флажка SHM_RND
в аргументе shmflag
:
• Если флажок SHM_RND
не установлен, система присоединяет разделяемую память к указанному shmaddr
адресу.
• Если флажок SHM_RND
установлен, система присоединяет разделяемую память к адресу, полученному округлением в меньшую сторону shmaddr
до некоторой определенной величины SHMLBA
.
По умолчанию разделяемая память присоединяется с правами на чтение и запись. Эти права можно изменить, указав флажок SHM_RDONLY
в аргументе shmflag
.
Таким образом, несколько процессов могут отображать область разделяемой памяти в различные участки собственного виртуального адресного пространства, как это показано на рис. 3.20.
Рис. 3.20. Совместное использование разделяемой памяти
Окончив работу с разделяемой памятью, процесс отключает (detach) область вызовом
#include
#include
#include
int shmdt(char *shmaddr);
При работе с разделяемой памятью необходимо синхронизировать выполнение взаимодействующих процессов: когда один из процессов записывает данные в разделяемую память, остальные процессы ожидают завершения операции. Обычно синхронизация обеспечивается с помощью семафоров, назначение и число которых определяется конкретным использованием разделяемой памяти.
Можно привести примерную схему обмена данными между двумя процессами (клиентом и сервером) с использованием разделяемой памяти. Для синхронизации процессов использована группа из двух семафоров. Первый семафор служит для блокирования доступа к разделяемой памяти, его разрешающий сигнал — 0, а 1 является запрещающим сигналом. Второй семафор служит для сигнализации серверу о том, что клиент начал работу. Необходимость применения второго семафора обусловлена следующими обстоятельствами: начальное состояние семафора, синхронизирующего работу с памятью, является открытым (0), и вызов сервером операции заблокирует обращение к памяти для клиента. Таким образом, сервер должен вызвать операцию mem_lock
только после того, как разделяемую память заблокирует клиент. Назначение второго семафора заключается в уведомлении сервера, что клиент начал работу, заблокировал разделяемую память и начал записывать данные в эту область. Теперь, при вызове сервером операции mem_lock его выполнение будет приостановлено до освобождения памяти клиентом, который делает это после окончания записи строки "Здравствуй, Мир!".
#define MAXBUFF 80
#define PERM 0666
/* Структура данных в разделяемой памяти */
typedef struct mem_msg {
int segment;
char buff[MAXBUFF];
} Message;
/* Ожидание начала выполнения клиента */
static struct sembuf proc_wait[1] = { 1, -1, 0 };
/* Уведомление сервера о том, что клиент начал работу */
static struct sembuf proc_start[1] = {
1, 1, 0
};
/* Блокирование разделяемой памяти */
static struct sembuf mem_lock[2] = {
0, 0, 0,
0, 1, 0
};
/* Освобождение ресурса */
static struct sembuf mem_unlock[1] = {
0, -1, 0
};
#include
#include
#include
#include
#include "shmem.h"
main {
Message* msgptr;
key_t key;
int shmid, semid;
/* Получим ключ, Один и тот же ключ можно использовать как
для семафора, так и для разделяемой памяти */
if ((key = ftok("server", 'A')) < 0) {
printf("Невозможно получить ключ\n");
exit(1);
}
/* Создадим область разделяемой памяти */
if ((shmid = shmget(key, sizeof(Message),
PERM | IPC_CREAT)) < 0) {
printf("Невозможно создать область\n");
exit(1);
}