← Назад к вопросам
Какая функция создаёт объект разделяемой памяти?
3.0 Senior🔥 101 комментариев
#Linux и операционные системы#Многопоточность и синхронизация
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Функции создания разделяемой памяти
Для создания объектов разделяемой памяти в POSIX-системах используется несколько функций в зависимости от типа ресурса, который вы хотите разделить между процессами. Это критично для написания многопроцессных приложений и IPC (Inter-Process Communication) механизмов.
Основные функции создания разделяемой памяти
1. shmget() — для System V shared memory
Функция создаёт или получает доступ к сегменту разделяемой памяти:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cstring>
#include <iostream>
int main() {
// Создаём сегмент разделяемой памяти размером 1024 байта
int shmid = shmget(IPC_PRIVATE, // или key_t key
1024, // размер в байтах
IPC_CREAT | // создать, если не существует
0666); // права доступа
if (shmid == -1) {
perror("shmget failed");
return 1;
}
std::cout << "Shared memory ID: " << shmid << std::endl;
// Удалить сегмент
shmctl(shmid, IPC_RMID, nullptr);
return 0;
}
2. shmat() — подключение к разделяемой памяти
После создания сегмента нужно подключить его к адресному пространству процесса:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cstring>
#include <iostream>
int main() {
// Создаём сегмент
int shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0666);
// Подключаемся к сегменту
void* shmaddr = shmat(shmid, // ID сегмента
nullptr, // адрес (nullptr = автоматический)
0); // флаги (0 = чтение/запись)
if (shmaddr == (void*)-1) {
perror("shmat failed");
return 1;
}
// Теперь можем работать с памятью
char* shared_data = (char*)shmaddr;
strcpy(shared_data, "Hello from process!");
// Отключиться от сегмента
shmdt(shmaddr);
// Удалить сегмент
shmctl(shmid, IPC_RMID, nullptr);
return 0;
}
POSIX Shared Memory: mmap()
Современный подход использует mmap() с файлом или с /dev/zero:
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
int main() {
const int SIZE = 1024;
// Способ 1: через обычный файл
int fd = open("shared_file.bin", O_CREAT | O_RDWR, 0666);
if (fd == -1) {
perror("open failed");
return 1;
}
// Изменяем размер файла
lseek(fd, SIZE - 1, SEEK_SET);
write(fd, "", 1);
// Отображаем файл в память
void* addr = mmap(nullptr, // адрес (nullptr = автоматический)
SIZE, // размер
PROT_READ | PROT_WRITE, // права доступа
MAP_SHARED, // разделяемое отображение
fd, // файловый дескриптор
0); // смещение в файле
if (addr == MAP_FAILED) {
perror("mmap failed");
return 1;
}
// Работаем с памятью
char* data = (char*)addr;
strcpy(data, "Shared via mmap!");
// Синхронизируем изменения на диск
msync(addr, SIZE, MS_SYNC);
// Отображаем
munmap(addr, SIZE);
close(fd);
return 0;
}
POSIX Named Shared Memory: shm_open()
Современный POSIX способ создания именованной разделяемой памяти:
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
int main() {
const int SIZE = 4096;
const char* SHM_NAME = "/myapp_shared_memory";
// Создаём или открываем именованный объект разделяемой памяти
int shm_fd = shm_open(SHM_NAME, // имя
O_CREAT | O_RDWR, // флаги создания
0666); // права доступа
if (shm_fd == -1) {
perror("shm_open failed");
return 1;
}
// Устанавливаем размер
if (ftruncate(shm_fd, SIZE) == -1) {
perror("ftruncate failed");
return 1;
}
// Отображаем в память
void* addr = mmap(nullptr, SIZE,
PROT_READ | PROT_WRITE,
MAP_SHARED,
shm_fd, 0);
if (addr == MAP_FAILED) {
perror("mmap failed");
return 1;
}
// Используем память
char* data = (char*)addr;
strcpy(data, "POSIX shared memory!");
// Очистка
munmap(addr, SIZE);
close(shm_fd);
shm_unlink(SHM_NAME); // удалить объект разделяемой памяти
return 0;
}
Сравнение методов
| Функция | Тип | Использование | Преимущества | Недостатки |
|---|---|---|---|---|
| shmget() | System V | Наследование, совместимость | Работает везде | Сложнее управлять |
| mmap() | POSIX file | Файловое отображение | Гибкость | Привязано к файлу |
| shm_open() | POSIX named | Современные приложения | Простота, названия | Только POSIX |
| memory_mapped_file | Windows | IPC на Windows | Эффективность | ОС-зависимая |
Практический пример: многопроцессная работа
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
struct SharedData {
int counter;
char message[256];
};
int main() {
key_t key = ftok("/tmp", 65); // генерируем ключ
int shmid = shmget(key, sizeof(SharedData), IPC_CREAT | 0666);
SharedData* shared = (SharedData*)shmat(shmid, nullptr, 0);
if (fork() == 0) {
// Дочерний процесс
for (int i = 0; i < 5; i++) {
shared->counter++;
sleep(1);
}
shmdt((void*)shared);
} else {
// Родительский процесс
sleep(2);
std::cout << "Counter: " << shared->counter << std::endl;
shmdt((void*)shared);
shmctl(shmid, IPC_RMID, nullptr);
}
return 0;
}
Лучшие практики
- Используйте shm_open() для новых приложений (POSIX стандарт)
- Синхронизируйте доступ через мьютексы или семафоры
- Проверяйте ошибки всех функций (shmget(), shmat(), mmap())
- Очищайте ресурсы через shmdt(), shmctl() или shm_unlink()
- Тестируйте на разных ОС, если требуется портативность
Выбор функции зависит от требований: System V сегменты для совместимости, POSIX функции для современных приложений.