| SHMOP(2) | System Calls Manual | SHMOP(2) |
shmat, shmdt - операции с общей памятью System V
Стандартная библиотека языка C (libc, -lc)
#include <sys/shm.h>
void *shmat(int shmid, const void *_Nullable shmaddr, int shmflg); int shmdt(const void *shmaddr);
Вызов shmat() подключает сегмент общей памяти System V с идентификатором shmid к адресному пространству вызывающего процесса. Адрес подключения, указанный в shmaddr, учитывается следующим образом:
В дополнении к SHM_RND, в аргументе битовой маски shmflg могут быть указаны следующие флаги:
Значение brk(2) вызывающего процесса от подключения не изменяется. При завершении работы процесса сегмент будет автоматически отсоединён. Один и тот же сегмент может быть подключён в адресное пространство процесса несколько раз, как только для чтения, так и для чтения-записи.
При успешном выполнении системный вызов shmat() обновляет поля структуры shmid_ds (см. shmctl(2)), связанной с общим сегментом памяти, следующим образом:
Вызов shmdt() отключает сегмент общей памяти, находящийся по адресу shmaddr, от адресного пространства вызывающего процесса. Отключаемый сегмент должен быть подключён по адресу shmaddr с помощью вызова shmat().
При успешном выполнении вызов shmdt() обновляет поля структуры shmid_ds, связанной с общим сегментом памяти, следующим образом:
On success, shmat() returns the address of the attached shared memory segment; on error, (void *) -1 is returned, and errno is set to indicate the error.
On success, shmdt() returns 0; on error -1 is returned, and errno is set to indicate the error.
shmat() может завершиться ошибкой из-за следующих ошибок:
shmdt() может завершиться ошибкой с одной из следующих ошибок:
POSIX.1-2008.
POSIX.1-2001, SVr4.
В SVID 3 (возможно, чуть раньше) тип аргумента shmaddr изменён с char * на const void *, а тип возвращаемого значения shmat() с char * на void *.
При вызове fork(2) потомки наследуют подключённые общие сегменты памяти.
При вызове execve(2) все подключённые общие сегменты памяти отключаются.
При вызове _exit(2) все подключённые общие сегменты памяти отключаются.
Для улучшения переносимости программ при подключении общего сегмента памяти рекомендуется использовать shmat() с аргументом shmaddr, установленным в NULL. Необходимо учитывать, что сегмент памяти, подключаемый таким способом, в разных процессах может подключаться по разным адресам. Поэтому все указатели в области общей памяти должны быть не абсолютными, а относительными (как правило относительно адреса начала сегмента).
В Linux сегмент общей памяти можно подключить даже, если он помечен для удаление. Однако в POSIX.1 об этом ничего не сказано, и многие другие реализации это не поддерживают.
На работу shmat() влияют следующие системные параметры:
Реализацией не ограничивается количество общих сегментов общей памяти на процесс (SHMSEG).
The two programs shown below exchange a string using a shared memory segment. Further details about the programs are given below. First, we show a shell session demonstrating their use.
In one terminal window, we run the "reader" program, which creates a System V shared memory segment and a System V semaphore set. The program prints out the IDs of the created objects, and then waits for the semaphore to change value.
$ ./svshm_string_read shmid = 1114194; semid = 15
In another terminal window, we run the "writer" program. The "writer" program takes three command-line arguments: the IDs of the shared memory segment and semaphore set created by the "reader", and a string. It attaches the existing shared memory segment, copies the string to the shared memory, and modifies the semaphore value.
$ ./svshm_string_write 1114194 15 'Hello, world'
Returning to the terminal where the "reader" is running, we see that the program has ceased waiting on the semaphore and has printed the string that was copied into the shared memory segment by the writer:
Hello, world
The following header file is included by the "reader" and "writer" programs:
/* svshm_string.h
Licensed under GNU General Public License v2 or later. */ #ifndef SVSHM_STRING_H #define SVSHM_STRING_H #include <stdio.h> #include <stdlib.h> #include <sys/sem.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0) union semun { /* Used in calls to semctl() */
int val;
struct semid_ds *buf;
unsigned short *array; #if defined(__linux__)
struct seminfo *__buf; #endif }; #define MEM_SIZE 4096 #endif // include guard
The "reader" program creates a shared memory segment and a semaphore set containing one semaphore. It then attaches the shared memory object into its address space and initializes the semaphore value to 1. Finally, the program waits for the semaphore value to become 0, and afterwards prints the string that has been copied into the shared memory segment by the "writer".
/* svshm_string_read.c
Licensed under GNU General Public License v2 or later. */ #include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #include "svshm_string.h" int main(void) {
int semid, shmid;
char *addr;
union semun arg, dummy;
struct sembuf sop;
/* Create shared memory and semaphore set containing one
semaphore. */
shmid = shmget(IPC_PRIVATE, MEM_SIZE, IPC_CREAT | 0600);
if (shmid == -1)
errExit("shmget");
semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
if (semid == -1)
errExit("semget");
/* Attach shared memory into our address space. */
addr = shmat(shmid, NULL, SHM_RDONLY);
if (addr == (void *) -1)
errExit("shmat");
/* Initialize semaphore 0 in set with value 1. */
arg.val = 1;
if (semctl(semid, 0, SETVAL, arg) == -1)
errExit("semctl");
printf("shmid = %d; semid = %d\n", shmid, semid);
/* Wait for semaphore value to become 0. */
sop.sem_num = 0;
sop.sem_op = 0;
sop.sem_flg = 0;
if (semop(semid, &sop, 1) == -1)
errExit("semop");
/* Print the string from shared memory. */
printf("%s\n", addr);
/* Remove shared memory and semaphore set. */
if (shmctl(shmid, IPC_RMID, NULL) == -1)
errExit("shmctl");
if (semctl(semid, 0, IPC_RMID, dummy) == -1)
errExit("semctl");
exit(EXIT_SUCCESS); }
The writer program takes three command-line arguments: the IDs of the shared memory segment and semaphore set that have already been created by the "reader", and a string. It attaches the shared memory segment into its address space, and then decrements the semaphore value to 0 in order to inform the "reader" that it can now examine the contents of the shared memory.
/* svshm_string_write.c
Licensed under GNU General Public License v2 or later. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/sem.h> #include <sys/shm.h> #include "svshm_string.h" int main(int argc, char *argv[]) {
int semid, shmid;
char *addr;
size_t len;
struct sembuf sop;
if (argc != 4) {
fprintf(stderr, "Usage: %s shmid semid string\n", argv[0]);
exit(EXIT_FAILURE);
}
len = strlen(argv[3]) + 1; /* +1 to include trailing '\0' */
if (len > MEM_SIZE) {
fprintf(stderr, "String is too big!\n");
exit(EXIT_FAILURE);
}
/* Get object IDs from command-line. */
shmid = atoi(argv[1]);
semid = atoi(argv[2]);
/* Attach shared memory into our address space and copy string
(including trailing null byte) into memory. */
addr = shmat(shmid, NULL, 0);
if (addr == (void *) -1)
errExit("shmat");
memcpy(addr, argv[3], len);
/* Decrement semaphore to 0. */
sop.sem_num = 0;
sop.sem_op = -1;
sop.sem_flg = 0;
if (semop(semid, &sop, 1) == -1)
errExit("semop");
exit(EXIT_SUCCESS); }
brk(2), mmap(2), shmctl(2), shmget(2), capabilities(7), shm_overview(7), sysvipc(7)
Русский перевод этой страницы руководства разработал(и) Alexander Golubev <fatzer2@gmail.com>, Azamat Hackimov <azamat.hackimov@gmail.com>, Hotellook, Nikita <zxcvbnm3230@mail.ru>, Spiros Georgaras <sng@hellug.gr>, Vladislav <ivladislavefimov@gmail.com>, Yuri Kozlov <yuray@komyakino.ru>, Иван Павлов <pavia00@gmail.com> и Kirill Rekhov <krekhov.dev@gmail.com>
Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.
Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков.
| 15 июня 2024 г. | Справочные страницы Linux 6.9.1 |