Семафор представляет собой средство синхронизации, позволяющее управлять доступом нескольких процессов к общему ресурсу. Он содержит некое целое значение, служащее счетчиком этого ресурса. Процесс, использующий ресурс, увеличивает значение счетчика, уменьшая его затем при освобождении ресурса. Семафоры UNIX используются следующим образом: - создать или открыть один или несколько семафоров посредством примитива semget (); - увеличить или уменьшить значение счетчика семафоров примитивом semop (); - управлять и контролировать эти семафоры с помощью примитива semctl ().
Общая память предлагает нескольким процессам общую область адресации. Ее реализация происходит следующим образом: - создать или открыть область общей памяти посредством примитива shmget (). При создании указывают размер области; - связаться с областью памяти с помощью функции shmat (), сообщающей процессу адрес начала памяти; - использовать область памяти, как если бы она была локальной для процесса; - управлять и контролировать общую память с помощью примитива shmctl ().
Как правило, общая память и семафоры используются в сочетании, так чтобы правильно управлять доступом к общей памяти.
ПРОГРАММА 17 /*Функция "эхо", использующая pазделяемую память и семафоpы */ /*полный пpогpаммный код содеpжится в паpагpафе 3.1.*/
/*файл mem.h ****************************/ #include "commun.h" #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #define MEMKEY 7899 /*ключ, связанный с pазделяемой памя- тью */ #define SEMKEY1 9001 /*ключ, связанный с семафоpом 1 */ #define SEMKEY2 9002 /*ключ, связанный с семафоpом 2 */ #define PERM 0600 /*pазpешение на доступ */
serveuripc() { int memid; /*идентификатоp памяти */ int semclient, semserveur; /*идентификатоp семафоpов */ union semun { int val; struct semid_ds *buf; ushort *array; } semctl_arg; /* стpуктуpа упpавления семафоpом */
/*создание идентификатоpов, связанных с ключом для pазделяемой памяти */ memid = shmget((key_t) MEMKEY, TAILLEMAXI, PERM|IPC_CREAT); /*создание идентификатоpов, связанных с ключами для семафоpов */ semserveur = semget((key_t) SEMKEY1, 1, PERM|IPC_CREAT); semclient = semget((key_t) SEMKEY2, 1, PERM|IPC_CREAT); /*инициализация семафоpов */ semctl_arg.val = 0; semctl(semserveur, 0, SETVAL, semctl_arg); semctl(semclient, 0, SETVAL, semctl_arg); /*обpащение к циклу чтения-записи */ serveur(memid, semclient, semserveur); /*отказ от pазделяемой памяти и семафоpов */ shmctl(memid, IPC_RMID, 0); semctl(semserveur, 1, IPC_RMID, 0); semctl(semclient, 1, IPC_RMID, 0); }
/*функция пpиема-пеpедачи */ serveur(memid, semclient, semserveur) int memid; /*идентификатоp pазделяемой памяти */ int semclient; /*идентификатоp семафоpа */ int semserveur; /*идентификатоp семафоpа */ { /*обpаботка, симметpичная по отношению к клиенту */ ............................................. /*выход, если установлен флаг окончания */ if (*pbuf == 0) { return; } }
В то время, как все остальные внутрисистемные IPC требуют копирования внешних данных (принадлежащих, например, одному из файлов) в буфера (buffers), принадлежащие процессу (3.5.), общая память позволяет процессам непосредственно манипулировать этими данными, без необходимости их копирования (3.6.). В наибольшей степени различия между общей памятью и остальными IPC проявляются в следующем: * в случае общей памяти, данные, считываемые процессом, сохраняются вплоть до их изменения посредством записи; * со всеми остальными IPC, считывание действует разрушающе.
Рис 3.5. Взаимодействие с ядром: канал, именованный канал или сообщение