Вы здесь

Классический API System V IPC

Пространство имён

Объекты System V IPC идентифицируется 32-битным ключом IPC, играющего роль, аналогичную имени файла. При создании объекта IPC ему присваивается уникальный 32-битный идентификатор IPC, аналогичный inode файла. Идентификаторы IPC назначаются ядром, ключи IPC произвольно выбираются программистами.

Особое значение ключа IPC_PRIVATE адресует объект, доступный только данному процессу и его потомкам. Данное значение позволяет избежать случайного доступа к посторонним объектам из-за конфликта ключей.

В случае совпадения идентификаторов несколько программ будут пытаться получить доступ к одному и тому же объекту. Не существует механизма, гарантирующего выбор уникального ключа IPC, поэтому была создана специальная функция ftok(), генерирующая ключ на основе уникального имени файла в файловой системе (точнее номера его Inode) и дополнительного байта (номера проекта). При выборе файла, для формирования ключа, необходимо обеспечить достаточную длительность его жизни. Если файл удалён, то новые процессы не смогут сгенерировать ключи доступа к объектам IPC на основе данного файла. Удаление файла и создание нового с тем же именем так же нарушит доступ к объектам IPC поскольку новый файл будет иметь отличный номер Inode.

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

   key_t ftok("/home/bob/key_base", 'Z');

Реализация ftok() в glibc

  if (__xstat64 (_STAT_VER, pathname, &st) < 0)
    return (key_t) -1;
  key = ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16)
         | ((proj_id & 0xff) << 24));
  return key;

Создание и удаление объектов

Объекты IPC создаются функциями msgget(), semget(), shmget().

При создании используются флаги

  • IPC_CREAT - Создать объект если он не существовал
  • IPC_EXCL - Совместно с IPC_CREAT - вернуть ошибку если объект существует

и права доступа. Права доступа аналогичны файлам (mode - rw-rw-rw-)

Управление объектами SysV IPC (в том числе их уничтожение) производится c помощью функций msgctl(), semctl(), shmctl(). Параметр cmd этих функций может принимать значения:

  • IPC_RMID - удалить объект
  • IPC_SET - изменить свойства объекта
  • IPC_STAT - получить свойства объекта

Флаги операций

Во всех операциях с объектами может быть указан дополнительный флаг

  • IPC_NOWAIT - возвратить ошибку если операция не может быть выполнена немедленно

Очередь сообщений

При создании очереди она ассоциируется с буфером размером MSGMNB (16384 байт в Linux).

Сообщение состоит из заголовка фиксированной длины и текста переменной длины. Размер текста не должен превышать MSGMAX (8192 байта в Linux).

Каждое сообщение поступает в очередь, где хранится до тех пор, пока кто-нибудь не прочитает его. После прочтения сообщение удаляется из очереди сообщений. Следовательно, только один процесс может получить конкретное сообщение.

Сообщение может быть помечено целочисленным значением (типом сообщения), которое позволяет процессу избирательно извлекать сообщения из очереди. Правила чтения по типам:

  • если msgp равен нулю, то используется первое сообщение из очереди;
  • если msgp больше нуля, то из очереди берется первое сообщение типа msgp (если только в параметре msgflg не выставлен флаг MSG_EXCEPT. В этом случае из очереди берется первое сообщение, тип которого не равен msgp).
  • если msgp меньше нуля, то из очереди берется первое сообщение со значением, меньшим, чем абсолютное значение msgp.

    #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h>

    int msgget(key_t key, int msgflg); int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

    struct msgbuf { long mtype; /* message type, must be > 0 / char mtext[1]; / message data */ };

    int msgctl(int msqid, int cmd, struct msqid_ds *buf);

Семафоры

Каждый семафор IPC представляет собой набор из одного или нескольких целочисленных счётчиков. Таким образом один семафор может защищать несколько объектов. Обычно, нулевое значение счётчика означает, что объект свободен, положительное - занят, но можно договориться о других значениях. Механизм семафоров ничего не знает про их использование, а только обеспечивает атомарные операции изменения значений.

Существуют ограничения как на количество семафоров (по умолчанию 128), так и на количество счётчиков внутри одного семафора (по умолчанию 250). Эти данные в Linux доступны в /proc/sys/kernel/sem.

При завершении процесса все операции, которые он проводил над семафорами сбрасываются, что позволяет избежать неприятностей в случае краха процесса, изменившего значения счётчиков.

Операции над семафорами в вызове semop():

  • Если величина sembuf[n].semop положительна, то текущее значение счётчика n увеличивается на эту величину.
  • Если значение sembuf[n].semop равно нулю, процесс ожидает, пока счётчик n не обнулится.
  • Если величина sembuf[n].semop отрицательна, процесс ожидает, пока значение счётчика n не станет большим или равным абсолютной величине sembuf.semop. Затем абсолютная величина sembuf[n].semop вычитается из значения счётчика n.

    #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h>

    int semget(key_t key, int nsems, int semflg); int semop(int semid, struct sembuf *sops, unsigned nsops);

    struct sembuf { unsigned short sem_num; /* semaphore number / short sem_op; / semaphore operation / short sem_flg; / operation flags */ }

    int semctl(int semid, int semnum, int cmd, ...);

Общая память

Вызов shmget() резервирует участок физической памяти (фала подкачки)

Вызов shmat() (attach) отображает зарезервированный участок физической памяти в виртуальное адресное пространство процесса.

Вызов shmdt() (detach) разрывает связь между зарезервированным участок физической памяти и виртуальным адресным пространством процесса.

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

   int shmget(key_t key, size_t size, int shmflg);
   void *shmat(int shmid, const void *shmaddr, int shmflg);
   int shmdt(const void *shmaddr);
   int shmctl(int shmid, int cmd, struct shmid_ds *buf);
Яндекс.Метрика