Программирование >>  Структура ядра и системные вызовы 

1 ... 56 57 58 [ 59 ] 60 61 62 ... 98


enum ipc op { GETMEM, SND RPy, RCV REQ, RESET SEM }; public:

/* функция-конструктор */ message( int key }

/* создать разделяемую область памяти */ ostrstream{mfile,sizeof mfile) FOO key NO; int fd = shm open{mfile, 0 CREAT0 RDWR,

S IRWXUIS IRWXGIS IRWXO}; if {fd==-l) { perror{ shm open ); return; } {void}ftruncate{fd,sizeof(struct shm header}};

/* отобразить разделяемую область памяти в адресное

пространство процесса */ if {(memptr=(struct shm header*}mmap{О, sizeof(struct shm header},

PROT READ I РЮТ ИР1ТЕ, MAP SHARED, fd, 0}) = MAP FAILED} { perror( mmap }; return;

close(fd);

/* создать семафор для разделяемой области памяти */ ,

sem id = (sem t*)&memptr->semaphore; if ({sem init{sem id, 1, 1}}==-1) perror{ sem init };*J

/* инициализировать список сообщений как пустой */ for {int i=0; i < MAX MSG; i++}

memptr->msgList[i}.mtype = INT MIN;

/* функция-деструктор: отсоединить разделяемую область

памяти от процесса */ ~message{} { munmap{memptr, sizeof(struct shm header}}; };

/* проверить статус создания разделяемой области памяти */ int good{} { return {memptr) ? 1 : 0; };

/* удалить разделяемую область памяти и семафоры */

int rmQ{}

if {sem destroy(sem id)==-l) perror( sem destroy }; if (shm unlink{mfile}==-1) perror( shm unlink ); return munmap(memptr, sizeof{struct shm header)};

/* попробовать изменить значение семафора */

void getsem( enum ipc op opType )

switch {opType) { case GET MEM: case RCV REQ:

if (sem wait{sem id)==-1) perror( sem wait };

break; case SND RPY: case RESET SEM:

if (sem post{Sem id)==-l} perror{ sem post };

break;

}; /* getsem */

/* передать сообщение в очередь сообщений*/ int send( const void* buf, int size, int type) {

getsem(GET MEM); изменить значение семафора

for (int i=0; i < MAX MSG; i++) if (memptr->msgList[i}.mtype==INT MIN} { /* найти пустую позицию в очереди сообщений для сохранения данного сообщения */ \ :-

memcpy(memptr->msgList[i} .mtext, buf, size>:1 memptr->msgList{i] .mtext[size] = XO; ?, memptr->msgList[i].mtype = type;

break;

if (i >= MAX MSG) { очередь сообщений заполнена

cerr Too many messages in the queue!\n ; return -1; возвратить код неудачного завершения

getsem{SND RPy}; увеличить значение семафора;

return 0; возвратить код успешного завершения

}; /* send */

/* принять сообщение */

int rcv{ void* buf, int size, int type, int* rtype)

do {

getsem(RCV REQ); изменить значение семафора

int lowest type = -1; for {int i=0; i < MAX MSG; i++) {

if (memptr->msgList[i].mtype==INT MIN) continue;

/* закончить, если type = 0 или совпадает с типом сообщения */

if (itype II type==memptr->msgList[i].mtype) break; /* если type < 0, найти наименьший тип сообщения < type */ if {type < O.&S -type >= memptr->msgList[i].mtype} if (lowest type==-l (memptr->msgList[i].mtype < memptr->msgList[lowest type].mtype)) lowest type = i;

if (i < MAX MSG I I lowest type !=-l} { найти одно

сообщение

if (lowest type!=-l}i = lowest type;

/* скопировать текст сообщения и его тип в переменные вызывающего процесса */



memcpy(buf,meraptr->msgList[i].mtext,

strlen(memptr->msgList[i].mtext)+1); if (rtype) *rtype = memptr->msgList[i].mtype; /* отметить позицию очереди как пустую */ memptr->msgList[i].mtype = INT MIN; getsem(RESET SEM); увеличить значение семафора return strlen((char*)buf); возвратить размер

сообщения

увеличить значение семафора подождать 1 секунду проверить очередь повторно

getsem(RESET SEM);

sleep(1);

) while(1); }; /* rev */ ); /* message */ ♦endif

Новый класс message отличается от класса message, представленного в разделе 10.7.7. Это обусловлено тем, что семафоры POSIX.Ib принимают целые значения, которые могут всякий раз изменяться только на 1. Значения же семафоров System V разрешается изменять на любую целую величину. Вследствие этого ограничения новый класс message не поддерживает взаимодействие между сервером и одним из клиентов в случае, если остальные клиентские процессы блокируются своими собственными вызовами semop. В результате получается новый класс message, код которого проше: каждый запрос send и receive предваряется вызовом sem waitдля получения совместно используемого семафора. Этот вызов завершается вызовом sem post, который освобождает данный семафор для разблокирования других процессов (серверных и клиентских), требуюших доступа к очереди сообшений. Кроме того, класс message теперь полнее реализует возможности, заложенные в механизмах обмена сообшениями, используемых в System V и POSIX.Ib.

Функция-конструктор этого класса получает в качестве аргумента целочисленный ключ и задает имя для разделяемой области памяти. Эта область памяти выделяется посредством вызова shmopen. Процесс может читать данные из вновь выделенной области и записывать их в нее, а для владельца, группы и прочих пользователей устанавливаются права доступа на чтение, запись и выполнение (в случае, если до вызова данная область памяти не сушествует).

Размер выделенной разделяемой области памяти с помошью вызова ftruncate устанавливается равным размеру, заданному в struct shmjieader Эта структура определяет все поля данных для одной разделяемой области памяти - значения совместно используемого семафора и список записей, в которых хранятся сообшения сервера и клиента.

Разделяемая область памяти отображается в виртуальное адресное пространство процесса при помоши функции ттар. Начальный адрес отображаемой памяти определяется ядром. После вызова ттар дескригттор файла, возвращенный вызовом shmjopen, закрывается (он больше не нужен). Затем с помощью вызова semjopen создается семафор. Этот новый семафор

размещается в начале совместно используемой области памяти, и его начальное значение устанавливается равным 1.

Наконец, список сообщений инициализируется установкой типа каждого сообщения в INT MIN (большое отрицательное число). Такая установка показывает, что они не используются.

Когда сообщение передается в очередь функцией message.-.sent, сначала посредством вызова функции message:-.getsem изменяется значение семафора (эта функция вызывает sem wait). В результате этого вызова процесс открывает семафор и теперь может обращаться к списку сообщений, находящихся в очереди. Он просматривает каждый элемент списка сообщений, пока не находит первый свободный элемент списка (тип которого INT MIN). Процесс заносит в эту запись данные сообщения (текст и тип). После этого процесс освобождает семафор еще одним вызовом функции message:.getsem (которая вызывает sem post).

Когда процесс пытается принять сообщение из очереди с помощью функции message::rcv, сначала посредством функции message:.getsem изменяется значение семафора (названная функция вызывает semjwait). В результате такого вызова процесс открывает семафор и теперь может обращаться к списку сообщений, находящихся в очереди. Он просматривает каждый элемент списка сообщений, пока не находит запись, тип которой совпадает с типом сообщения, заданным вызывающим процессом. Процесс копирует текст и тип сообщения, содержащиеся в этой записи, в переменные, являющиеся аргументами функции, и закрывает семафор (посредством вызова функции message::getsem). Наконец, функция message::rcv возвращает вызывающему процессу размер сообщения. Если ни у одного сообщения, поступившего в очередь, тип не совпадает с типом, заданным вызывающим процессом, функция закрывает семафор, переводит процесс на одну секунду в состояние ожидания, а затем повторяет весь процесс получения сообщения. Таким образом вызывающий процесс блокируется до тех пор, пока в очередь не поступит сообщение, удовлетворяющее критериям поиска.

Функция message::rmQ вызывается для удаления разделяемой области Памяти и семафора. Эта задача реализуется путем вызова sem destroy (для удаления семафора), shmjunlink (для удаления разделяемой области памяти) и, наконец, типтар (для отсоединения разделяемой области памяти от виртуального адресного пространства процесса).

Новый заголовок message.h можно включить при компиляции клиентской и серверной программ так, как показано в разделе 10.3.7. Результат выполнения новых программ должен совпадать с результатом, приведенным в разделе 10.3.7.



10.10. Заключение

в этой главе рассматриваются методы межпроцессного взаимодействия, используемые в UNIX System V.3, V.4 и POSIX.lb: сообщения, семафоры, разделяемая память и API ттар. Подробно освещается синтаксис этих API и предлагаются примеры программ, иллюстрирующие их использование. Общий недостаток перечисленных методов IPC состоит в том, что не существует стандартов, которые определяли бы порядок их использования для межмашинного взаимодействия. В следующей главе будут рассмотрены такие методы межпроцессного взаимодействия, как гнезда (BSD UNIX) и TLI, интерфейс транспортного уровня (UNIX System V.3 и V.4). Гнезда и ТЫ позволяют обеспечить взаимодействие между процессами, которые выполняются как на одной машине, так и на разных.

ГЛАВА


Гнезда и интерфейс транспортного уровня

в предыдущей главе были рассмотрены методы межпроцессного взаимодействия, которые основаны на использовании сообщений, разделяемой памяти и семафоров. Эти методы хорошо приспособлены для организации взаимодействия процессов на одном компьютере, но не могут обеспечить взаимодействие процессов, работающих на разных машинах. Связано это с тем, что очереди сообщений, области разделяемой памяти и наборы семафоров обозначаются целочисленными ключами. Эти ключи уникальны только для отдельных компьютеров, но не для множества машин. Поэтому процесс, работающий на компьютере А, не может обратиться к очереди сообщений, созданной на машине В, с помощью только ключа этой очереди. Методы IPC, определенные стандартом POSIX. lb, позволяют решить данную проблему путем использования для обозначения сообщений, семафоров и разделяемой памяти текстовых имен. Этот стандарт предоставляет производителям систем право самим определять и интерпретировать указанные имена таким образом, чтобы механизм IPC мог работать и в компьютерной сети.

В системе BSD UNIX 4.2 бьши впервые введены гнезда (sockets), которые предоставляют независимые от протокола услуги по организации сетевого интерфейса и способны обеспечить работоспособность методов IPC в масштабах локальной сети. В частности, гнезда могут работать как с протоколом TCP (Transmission Control Protocol), так и с протоколом UDP (User Datagram Protocol). Обращаться к гнезду можно по IP-адресу хост-машины и номеру порта. Заданный таким образом адрес уникален в масштабах всей Internet, так как для каждой машины комбинация адреса и номера порта уникальна. Следовательно, два процесса, выполняемых на отдельных машинах, могут взаимодействовать друг с другом через гнезда.

Глава 11. Гнезда и интерфейс транспортного уровня



1 ... 56 57 58 [ 59 ] 60 61 62 ... 98

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика