|
Программирование >> Структура ядра и системные вызовы
Значение cmd Что должен сделать процесс IPC STAT Копировать управляющие параметры разделяемой области памя- ~ ти в объект, указанный аргументом buf IPC SET Заменить управляющие параметры разделяемой области памяти параметрами, определенными в объекте, на который указывает аргумент buf. Чтобы выполнить эту операцию, вызывающий j процесс должен иметь права привилегированного пользователя,! создателя или назначенного владельца разделяемой памяти. Рас-/ сматриваемый API может устанавливать только UID владельца области и идентификатор его группы, а также права доступа IPC RMID Удалить разделяемую область памяти из системы. Чтобы выпол нить эту операцию, вызывающий процесс должен иметь права привилегированного пользователя, создателя или назначенного , владельца области. Если к разделяемой области памяти, подлежащей удалению, подсоединены один или несколько процессов, то операция удаления будет отложена до тех пор, пока эти процессы не отсоединятся от нее SHM LOCK Блокировать разделяемую область памяти. Для выполнения этой операции вызывающий процесс должен обладать правами привилегированного пользователя SHM UNLOCK Разблокировать разделяемую область памяти. Для выполнения этой операции вызывающий процесс должен обладать правами привилегированного пользователя В случае успешного выполнения рассматриваемый API возвращает О, а в случае неудачи--1. Приведенная ниже программа tei/ /iw2 С открывает разделяемую память с ключевым идентификатором 100 и вызывает API shmcti для выборки управляющих параметров этой области. Если вызовы shmget и shmcti вьшол-няются успешно, процесс выводит на экран размер разделяемой области. Посредством еще одного вызова shmcti процесс устанавливает идентификатор владельца очереди равным своему UID. Наконец, вызвав shmcti в третий раз, процесс удаляет разделяемую область памяти. ♦include <iostream.h> ♦include <stdio.h> ♦ include <unistd.h>.j ♦include <sys/ipc.h> ♦include <sys/shm.h>~ int main{) { struct shmid ds sbuf; int fd = shmget (100, 1024, 0);, if (fd>0 &S shmcti(fd, IPC STAT,Ssbuf)) { cout shared memory size if: << sbuf.shm segsz endl; sbuf.shm perm.uid = getuidO; заменить UID владельца if (shmcti(fd,IPC SET,Ssbuf)==-l) perror( shmcti ); } else perror( shmcti ); if (shmcti(fd,IPC RMID,0)) perror( shmcti - IPC RMID ); return 0; 10.7.7. Пример приложения клиент/сервер с семафорами и разделяемой памятью В данном разделе описывается еще одна версия приложения клиент/сер-вер, которое мы рассматривали в разделе 10.3.7. Вместо сообщений здесь для организации очереди сообщений используются семафоры и разделяемая память. По этой причине заголовок message.h требует серьезной корректировки, однако интерфейс класса message клиентской и серверной программ, а также модули client. С и server. С - те же самые, которые описывались в разделе 10.3.7. В этом состоит преимущество применения классов С++: если внешние интерфейсы класса не меняются, то не нужно модифицировать ни одно приложение, которое использует этот класс, даже если внутренняя реализация класса существенно изменилась. Для создания очереди сообщений при помощи семафоров и разделяемой памяти в адресном пространстве ядра создается область памяти, совместно используемая для записи всех сообщений, передаваемых в эту очередь. Семафоры определяют, какой процесс может получить доступ к этой разделяемой области памяти (для чтения и записи сообщения) в каждый момент времени. В частности, может выполняться множество клиентских процессов, одновременно передающих запросы в серверный процесс и манипулирующих семафорами посредством одних и тех же системных вызовов semop. Обработка этих вызовов должна обеспечивать один из двух вариантов: либо все они блокируются, когда сервер активно работает с разделяемой памятью, либо только один из клиентских процессов активно работает с этой областью памяти (и тогда все остальные клиентские процессы и серверный процесс блокируются). Чтобы реализовать эти варианты, используются два семафора со следующими возможными значениями:
Клиентские процессы и серверный процесс взаимодействуют с этим набором семафоров следующим образом. Сначала сервер создает набор семафоров и разделяемую область памяти. Он инициализирует созданный набор значениями О, I (т.е. значение первого семафора - О, а значение второго семафора - I). Сервер ждет, когда клиент передаст запрос в разделяемую область памяти. Для этого он вьшолняет вызов semop с заданными значениями -I и 0. Такой вызов блокирует сервер, потому что текущее значение набора - О, 1 и ни один из семафоров набора не может быть изменен вызовом jemoj? со значениями-I, 0. Когда один или несколько клиентов пытаются передать сообщение в разделяемую область памяти, они выполняют вызов semop с заданными значениями 0,-1. Один из этих вызовов завершится успешно, потому что / на тот момент значение семафора будет равно О, 1. Клиентский процесс, успешно выполнив вызов semop, сразу же изменит значения семафоров на О, 0. В результате будут блокированы все остальные клиентские процессы, которые вьшолняют вызов semop со значением О, -1, а также сервер, выполняющий вызов semop со значением -1, 0. Клиентский процесс, изменивший значения набора семафоров, может теперь записать в разделяемую область памяти команду запроса на обслуживание и свой идентификатор. После этого он выполняет вызов semop со значением 1, 0. В результате серверный процесс разблокируется и может вызвать функцию semop, но новые значения семафоров будут по-прежнему блокировать остальные клиентские процессы, которые выполняют вызов semop со значением 0,-1. Если команда запроса на обслуживание - не QUITCMD, этот клиентский процесс выполнит вызов semop со значениями -1, -1 и заблокируется. Разблокированный сервер прочитает из разделяемой области памяти запрос на обслуживание, записанный клиентом. Если была записана команда QUIT CMD, сервер освободит разделяемую область памяти и набор семафоров, а затем завершит свою работу. Если записанная команда - не QUIT CMD, сервер запишет данные ответа в разделяемую область памяти, а затем выполнит вызов semop со значением 1, 1. Это разблокирует клиентский процесс, который выполняет вызов semop со значением -1, -1. Остальные клиентские процессы, которые выполняют вызов semop со значением 0,-1, остаются заблокированными новыми значениями семафоров. После вызова semop сервер возвращается в состояние ожидания запроса на обслуживание от нового клиента. Клиент, который разблокирован сервером, устанавливает значение набора семафоров в О, О и читает данные ответа сервера. Он посьшает данные на стандартное устройство вывода, а затем устанавливает значения семафоров в О, 1, после чего завершается. Последний вызов semop возвращает систему в состояние, в котором один из клиентов будет разблокирован и начнет взаимодействовать с сервером через разделяемую область памяти и семафоры. Последовательность изменения значений семафоров на различных этапах взаимодействия между клиентом и сервером представлена на рис. 10.6 (значения семафоров показаны в овалах). clients semop(0,1) Клиент читает ответ clients semор(-1,-1) Клиент может прочитать ответ clients semop(0,-1) --- записывает сообщение clients semop(0,1) clients semop(-1,0) Сервер читает сообщение и записывает ответ Рис. 10.6. Взаимодействие между клиентом и сервером с использованием семафоров и разделяемой области памяти Заголовок message.h, описанный в разделе 10.3.7, модифицируется под использование разделяемой области памяти и семафоров. Новый класс message объявляется в следующем заголовке messages.И: #ifndef MESSAGE3 H #define MESSAGE3 H ♦include <strstream.h> #include <stdio.h> finclude <stdlib.h> finclude <memory.h> finclude <unistd.h> finclude <sys/types.h> finclude <sys/ipc.h> finclude <sys/shm.h> finclude <sys/sem.h> finclude <sys/wait.h> finclude <sys/errno.h> /* общие объявления для серверного процесса и демона */ enum { MSGKEY=186, MAX LEN=256, SHMSIZE=1024, SEMSIZE=2 }; enum { LOCAL TIME = 1, UTC TIME = 2, QUIT CMD = 3, ILLEGAL CMD = 4, SEM RD = 0, SEM WR=1 }; struct mgbuf 1 long char mtype; mtext[MAX LEN]; class Tiessage private: int shmid, semId; struct mgbuf *msgPtr; enum ipc op ( RESET SEM, CLIENT GET MEM, CLIENT SND REQ, SERVER RCV REQ, SERVER GET MEM, SERVER SND RPY, CLIENT RCV RPY} ; public: /* лопробуем изменить значения семафоров */ void getsem( enum ipc op opType ) static struct sembuf args[2] = { {SEM RD}, {SEM WR) ); switch (opType) { case SERVER GET MEM: return; case CLIENT GET MEM: args[SEM RD].sem op = 0, args[SEM WR].sem op = -1; break; case CLIENT SND REQ: args[SEM RD].sem op = 1, , args[SEM WR].sem op = 0; break; case SERVER RCV REQ: args[SEM RD].sem op = -1, args[SEM WR].sem op = 0; break; case SERVER SND RPy: args[SEM RD}.sem op = 1, args[SEM WR].sem op = 1; break; case CLIENT RCV RPY: args[SEM RD}.sem op = -1, args[SEM WR}.sem op = -1; break; case RESET SEM: args [SEM RD} . sem op => 0, args[SEM WR].sem op = 1; if (semop(semId,args,SEMSIZE}==-1) perror( semop ); /* функция-конструктор */ message( int key ) if ((shmld=shmget(key, SHMSIZE, 0))==-!) { if (errno==ENOENT) { создать новый объект класса message if ((shmld= shmget(key, SHMSIZE, IPC CREAT0666) } ==-1) perror( shmget }; else if ((semid=semget(key, SEMSIZE, IPC CREAT0666})==-1) perror( semget ); else getsem(RESET SEM); инициализировать новый набор семафоров else perror( shmget ) ; else if ((semld=semget(key, 0, 0))==-1) /* получить значения существующих семафоров */ perror( semget ) ; if (shmld>=0 &&- ! (msgPtr=(struct mgbuf*)shmat(shmid,0,0)}} perror( shmat ! ; /* функция-деструктор */ -message 0 {}; /* проверить статус открытия очереди сообщений */ int goodO { return (shmid >= 0 && senild>=0) ? 1 : 0; }; /* удалить очередь сообщений */ int rmQO if (shmdt((char*)msgPtr)<0) perror( semdt ); if (!semcti(semId,0,IPC RMID,0} && !shmcti(shmid,IPC RMID, 0)) return 0; perror( shmcti or semcti ); return -1; }; , /* передать сообщение */ int send( const void* buf, int sizeJISnt type) { . .ЩГ int server = (type > 99),- ,! getsem(server ? SERVER GET MEM : CLIENT GET MEM); memcpy(msgPtr->mtext,buf,.size); msgPtr->mtext[size] = Л0; msgPtr->mtype = type; getsem(server ? SERVER SND RPy : CLIENT SND REQ}; return 0; /* принять сообщение */ int rcv( void* buf, int size, int type, int* rtype) { int server = (type < 0); getsem(server ? SERVER RCV REQ : CLIENT RCV RPY}; memcpy (buf ,msgPtr->mtext, strlen (msgPtr->mtext}+!) ; if (rtype) *rtype = msgPtr->mtype; if (!server) getsem(RESET SEM); return strlen(msgPtr->mtext); I* message */ #endif
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |