Какая функция создаёт объект разделяемой памяти в Linux?

Ответ

В Linux для создания сегмента разделяемой памяти (shared memory) используется системный вызов shmget().

Сигнатура:

#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);

Параметры:

  • key (key_t): Ключ для идентификации сегмента. Можно использовать IPC_PRIVATE для создания нового уникального сегмента, или сгенерировать ключ с помощью ftok().
  • size (size_t): Размер создаваемого сегмента в байтах.
  • shmflg (int): Флаги, определяющие права доступа (например, 0666) и режим создания. Часто используются комбинации:
    • IPC_CREAT: Создать сегмент, если он не существует.
    • IPC_EXCL: В комбинации с IPC_CREAT гарантирует, что вызов завершится ошибкой, если сегмент с таким ключом уже существует.

Возвращаемое значение: При успехе — целочисленный идентификатор сегмента разделяемой памяти (shmid). При ошибке — -1, и переменная errno устанавливается соответствующим образом.

Пример создания сегмента:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    // Создаём сегмент размером 1024 байта с правами чтения и записи для всех.
    // IPC_CREAT | 0666 означает: создать, если не существует, и дать права rw-rw-rw-.
    int shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0666);

    if (shmid == -1) {
        perror("shmget failed");
        exit(EXIT_FAILURE);
    }

    printf("Shared memory segment created with ID: %dn", shmid);

    // ... далее сегмент можно присоединить с помощью shmat()
    return 0;
}

После создания сегмента процессы используют shmat() для присоединения (получения указателя на эту память) и shmdt() для отсоединения. Управление жизненным циклом (удаление) осуществляется через shmctl() с командой IPC_RMID.

Ответ 18+ 🔞

Слушай, ну вот объясняю, как в Линуксе память общую между процессами сделать. Ситуация, блядь, классическая: один процесс насчитал что-то, а другому надо эти цифры прочитать, а копировать через файлы или сокеты — овердохуища возни. Вот для этого и придумали shmget(), чтобы кусок памяти на всех один был.

Представь, что это типа общежитие для данных. Чтобы его построить, нужен вызов shmget(). Выглядит он так, ёпта:

#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);

Разберём по косточкам, а то нихуя не понятно.

  1. key — это как номер квартиры в том самом общежитии. Все процессы, которые хотят в одну и ту же память, должны знать этот самый ключ. Можно взять специальное значение IPC_PRIVATE — тогда система сама выделит новый уникальный сегмент, но его ID потом надо будет как-то детям-процессам передать. А можно сгенерировать ключ функцией ftok() от пути к какому-нибудь файлу, чтобы все независимо могли его вычислить. Хуй с горы, в общем.

  2. size — это, блядь, размер твоей "комнаты" в байтах. Сколько памяти тебе надо, столько и проси. Только не жадничай, а то оперативка кончится.

  3. shmflg — вот тут самое интересное. Это флаги, комбинация из двух вещей:

    • Права доступа. Как в chmod0666 значит, что все могут и читать, и писать. 0644 — только хозяин пишет, остальные читают. Ставь, что душе угодно.
    • Режим создания. Самые важные — IPC_CREAT и IPC_EXCL.
      • IPC_CREAT — значит "создай сегмент, если его ещё нет". Если уже есть — просто верни его ID.
      • IPC_EXCL — эту штуку используют вместе с IPC_CREAT. И тогда смысл такой: "Создай новый сегмент, но если он УЖЕ существует — нахуй, выдай ошибку". Это чтобы два раза не создать одно и то же, понимаешь? Защита от дурака, а дурак часто — это ты сам.

Возвращает эта функция, ядрёна вошь, целое число — идентификатор сегмента (shmid). Это как пропуск в это самое общежитие. Если вернула -1 — всё, пизда, что-то пошло не так. Смотри в errno, что за косяк.

Ну а теперь, чтобы не быть пустым трёпом, вот тебе реальный код, как это делается:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    // Создаём сегмент размером 1024 байта с правами чтения и записи для всех.
    // IPC_CREAT | 0666 означает: создать, если не существует, и дать права rw-rw-rw-.
    int shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0666);

    if (shmid == -1) {
        perror("shmget failed");
        exit(EXIT_FAILURE);
    }

    printf("Shared memory segment created with ID: %dn", shmid);

    // ... далее сегмент можно присоединить с помощью shmat()
    return 0;
}

Смотри, что тут происходит: мы говорим системе — "дай нам новый уникальный сегмент (IPC_PRIVATE) на 1024 байта, создай его если надо (IPC_CREAT), и пусть все в него пишут и читают (0666)". Если получили -1 — ругаемся через perror и валим нахуй с ошибкой. Если всё ок — радостно печатаем ID.

И главное, запомни: shmget() — это только создание/получение сегмента. Чтобы им пользоваться, его надо присоединить к адресному пространству процесса функцией shmat() (она вернёт указатель, с которым можно работать как с обычной памятью). Закончил работать — отсоедини через shmdt(). А чтобы совсем удалить этот сегмент из системы (чтобы память не текла), нужна команда shmctl() с флагом IPC_RMID. Но это уже совсем другая история, блядь.