int fd;
size_t len; /* Размер объекта разделяемой памяти */
char *addr;
if (argc!= 3 || strcmp(argv[1], "-help") == 0)
usageErr("%s shm-name string\n", argv[0]);
fd = shm_open(argv[1], O_RDWR, 0); /* Открываем существующий объект */
if (fd == -1)
errExit("shm_open");
len = strlen(argv[2]);
if (ftruncate(fd, len) == -1) /* Изменяем размер объекта, чтобы вместить строку */
errExit("ftruncate");
printf("Resized to %ld bytes\n", (long) len);
addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
errExit("mmap");
if (close(fd) == -1) /* Дескриптор 'fd' больше не нужен */
errExit("close");
printf("copying %ld bytes\n", (long) len);
memcpy(addr, argv[2], len); /* Копируем строку в разделяемую память */
exit(EXIT_SUCCESS);
}
pshm/pshm_write.c
Программа из листинга 50.3 направляет в стандартный вывод строку, хранящуюся в существующем объекте разделяемой памяти, чье имя указано в виде аргумента командной оболочки. Выполнив функцию shm_open(), программа использует вызов fstat(), чтобы определить размер разделяемой памяти; полученное значение передается в вызов mmap(), который отображает объект. В конце строка выводится с помощью операции write().
Листинг 50.3. Копирование данных из объекта разделяемой памяти POSIX
pshm/pshm_read.c
#include
#include
#include
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
int fd;
char *addr;
struct stat sb;
if (argc!= 2 || strcmp(argv[1], "-help") == 0)
usageErr("%s shm-name\n", argv[0]);
fd = shm_open(argv[1], O_RDONLY, 0); /* Открываем существующий объект */
if (fd == -1)
errExit("shm_open");
/* Используем размер объекта разделяемой памяти в качестве длины
аргумента для вызова mmap() и количества байтов для операции write() */
if (fstat(fd, &sb) == -1)
errExit("fstat");
addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
errExit("mmap");
if (close(fd) == -1) /* Дескриптор 'fd' больше не нужен */
errExit("close");
write(STDOUT_FILENO, addr, sb.st_size);
printf("\n");
exit(EXIT_SUCCESS);
}
pshm/pshm_read.c
Использование программ из листингов 50.2 и 50.3 продемонстрировано в следующей сессии командной строки. Сначала создадим объект разделяемой памяти нулевой длины (воспользовавшись программой из листинга 50.1).
$ ./pshm_create — c /demo_shm 0
$ ls — l /dev/shm
total 4
— rw- 1 mtk users 0 Jun 21 13:33 demo_shm
Затем скопируем строку в объект разделяемой памяти с помощью программы из листинга 50.2:
$ ./pshm_write /demo_shm 'hello'
$ ls — l /dev/shm
total 4
— rw- 1 mtk users 5 Jun 21 13:33 demo_shm
Вывод, представленный выше, показывает: программа изменила размер объекта разделяемой памяти так, чтобы тот мог вместить заданную строку.
Теперь задействуем программу из листинга 50.3 для вывода строки из нашего объекта:
$ ./pshm_read /demo_shm
hello
Для координации доступа к разделяемой памяти обычно используются какие-нибудь средства синхронизации. В примере сессии, показанной выше, вся координация сводилась к тому, что пользователь запускал программы последовательно, одну за другой. Вместо этого рекомендуется применять механизм синхронизации (например, семафоры).
Стандарт SUSv3 требует, чтобы объекты разделяемой памяти имели сохраняемость как минимум на уровне ядра — то есть они должны существовать до тех пор, пока не будут удалены, или до перезагрузки системы. Когда объект разделяемой памяти больше не нужен, его следует удалить с помощью функции shm_unlink().
#include
int shm_unlink(const char *
Возвращает 0 при успешном завершении или -1 при ошибке
Функция shm_unlink() удаляет объект разделяемой памяти с именем name. Удаление не влияет на отображения объекта (которые будут существовать, пока соответствующие не завершатся или не выполнят вызов munmap()), но не позволят его открывать путем дальнейших вызовов shm_open(). Когда все процессы удалят свои отображения, объект будет уничтожен, а его содержимое утеряно.
Программа, представленная в листинге 50.4, применяет функцию shm_unlink() для удаления объекта разделяемой памяти, указанного в виде аргумента командной строки.
Листинг 50.4. Использование функции shm_unlink() для удаления объекта разделяемой памяти POSIX
pshm/pshm_unlink.c
#include
#include
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
if (argc!= 2 || strcmp(argv[1], "-help") == 0)
usageErr("%s shm-name\n", argv[0]);
if (shm_unlink(argv[1]) == -1)
errExit("shm_unlink");
exit(EXIT_SUCCESS);
}
pshm/pshm_unlink.c