Скачиваний:
90
Добавлен:
12.05.2015
Размер:
913.92 Кб
Скачать

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);

}

Соседние файлы в папке Chapter.4