Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 [ 113 ] 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

этих сообщений, хотя задачу можно и обобщить таким образом, чтобы он выполнял действия, аналогичные демону syslog, который описан в главе 13 [24]. Мы называем группу отправляющих сообщения процессов клиентами, потому что по отношению к нашему серверу они ими и являются, однако эти клиенты могут являться серверами по отношению к другим приложениям. Например, сервер Telnet является 1слиентом демона syslog, когда отправляет ему сообщения для занесения их в системный журнал.

Вместо передачи сообщений одним из описанных ранее методов (часть 2) будем хранить сообщения в разделяемой памяти, Это, разумеется, потребует какой-либо формы синхронизации действий клиентов, помещающих сообщения, и сервера, читающего их. На рис. 13.2 приведена схема приложения в целом.

клиент

клиент

клиент

>

сохранение /

I разделяемая память, в которой хранятся I семафоры и сообщения

1----- - - - - - -

создание и инициализация

>

, J

получение следующего сообщения и его вывод

сервер

Рис. 13.2. Несколько клиентов отправляют сообщения серверу через разделяемую память

Перед нами взаимодействие нескольких производителей (клиентов) и одного потребителя (сервер). Разделяемая память отображается в адресное пространство сервера и каждого из клиентов.

В листинге 13.8 приведен текст заголовочного файла cliserv2.li, в котором определена структура объекта, хранимого в разделяемой памяти.

Листинг 13.8. Заголовочный файл, определяющий содержимое разделяемой памяти

pxslitti/cliserv2.li 1 finclude unpipcli

2 fdefine MESGSIZE 256

3 fdefine NMESG 16

/* максимальные! размер сообщения в баР1тах. включая

завершающие* ноль */ /* максимальное количество сообщениР* */

4 5 6 7 8 9 10

struct shmstruct

sem t

sem t

sem t

long

sem t

mutex: nempty: nstored: nput:

noverflow: noverflowmutex:

/* структура, хранящаяся в разделяемой памяти */ /* три семафора Posix. размещаемые в па 1яти */

/* индекс для следующего сообщения */

/* количество переполнений */

/* взаимное исключение для счетчика переполнений */



11 long ttisgoff[NMESG]: /* сдвиг для каждого из сообщений */

12 char ttisgdata[NMESG * MESGSI2E]: /* сами сообщения */

13 }:

Основные семафоры и переменные

5-8 Три семафора Posix, размещаемых в памяти, используются для того же, для чего семафоры использовались в задаче производителей и потребителей в разделе 10.6. Их имена mutex, nempty, nstored. Переменная nput хранит индекс следующего помещаемого сообщения. Поскольку одновременно работают несколько производителей, эта переменная защищена взаимным исключением и хранится в разделяемой памяти вместе со всеми остальными.

Счетчик переполнений

9-10 Существует вероятность того, что клиент не сможет отправить сообщение из-за отсутствия свободного места для него. Если программа-клиент представляет собой сервер для других приложений (например, сервер РТР или HTTP), она не должна блокироваться в ожидании освобождения места для сообщения. Поэтому программа-клиент будет написана таким образом, чтобы она не блокировалась, но увеличивала счетчик переполнений (noverf low). Поскольку этот счетчик также является общим для всех процессов, он также должен быть защищен взаимным исключением, чтобы его значение не было повреждено.

Сдвиги сообщений и их содержимое

11-12 Массив msgof f содержит сдвиги сообщений в массиве msgdata, в котором сообщения хранятся подряд. Таким образом, сдвиг первого сообщения msgoff[0] = О, msgoff[l] = 256 (значение MESGSIZE), msgoff [2] = 512 и т. д.

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

В листинге 13.9 приведен текст программы-сервера, которая ожидает помещения сообщений в разделяемую память, а затем выводит их.

Листинг 13.9. Сервер, считывающий сообщения из разделяемой памяти

pxshtti/server2.c

1 finclude cliserv2.h

2 int

3 mainCint argc. char **argv)

5 int fd. index, lastnoverflow. temp:

6 long offset:

7 struct shmstruct *ptr:

8 if (argc != 2)

9 err quit( usage: server2 <name> ): продолжение



Листинг 13.9 (продолжение)

10 /* создание объекта разделяемое* памяти, установка размера, отображение в

память, закрытие дескриптора */

11 slntti unlinl<(Px 1pc nattie(argv[l])): /* ошибка игнорируется */

12 fd = Slntti open(PxJpc nattie(argv[l]). 0 RDWR 0 CREAT 0 EXCL. FILE MODE):

13 ptr = MttiapCNULL. SizeofCstruct slittistruct). PROT READ ] PROT WRITE.

14 MAP SHARED. fd. 0):

15 FtruncateCfd. sizeofCstruct slittistruct));

16 CloseCfd);

17 /* инициализация массива сдвигов */

18 for Cindex = 0; index < NMESG; index++)

19 ptr->ttisgoff[index] = index * MESGSIZE:

20 /* инициализация семафоров в разделяемоР* памяти */

21 Setti initC&ptr->ttiutex. 1. 1):

22 Sem initC8.ptr->nettipty. 1. NMESG):

23 SettiJnitC&ptr->nstored. 1. 0):

24 Setti initC8iptr->noverflowttiutex. 1. 1):

25 /* программа-потребитель */

26 index = 0;

27 lastnoverflow = 0:

28 for С : ; ) {

29 Setti waitC&ptr->nstored);

30 Setti wa i t С &pt r - >ttiutex);

31 offset = ptr->ttisgoff[index]:

32 printfCindex - d: *s\n . index. &ptr->ttisgdata[offset]):

33 if C++index >= NMESG)

34 index - 0: /* циклический буфер */

35 Setti postC&ptr->ttiutex):

36 Setti post С &pt r - >nettipty);

37 Setti waitC&ptr->noverflowttiutex):

38 tettip = ptr->noverflow; /* не выводим, пока не снимем блокировку */

39 Setti postC&ptr->noverflowttiutex);

40 if Ctettip != lastnoverflow) {

41 printfCnoverflow = *d\n . tettip):

42 lastnoverflow = tettip;

43 }

44 }

45 exitCO):

46 }

Создание объекта разделяемой памяти

10-16 Сначала делается вызов shni unlink, чтобы удалить объект с тем же именем, который мог остаться после другого приложения. Затем объект разделяемой памяти создается вызовом shni open и отображается в адресное пространство процесса вызовом ftimap, после чего дескриптор объекта закрывается.

Инициализация массива сдвигов

17-19 Массив сдвигов инициализируется сдвигами сообщений.



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 [ 113 ] 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.