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

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

13.5. Увеличение общего счетчика

Разработаем программу, аналогичную приведенной в разделе 12.3, - несколько процессов увеличивают счетчик, хранящийся в разделяемой памяти. Итак, мы помещаем счетчик в разделяемую память, а для синхронизации доступа к нему используем именованный семафор. Отличие программы из этого раздела от предыдущей состоит в том, что процессы более не являются родственными. Поскольку обращение к объектам разделяемой памяти Posix и именованным семафорам Posix осуществляется по именам, процессы, увеличивающие общий счетчик, могут не состоять в родстве. Достаточно лищь, чтобы каждый из них знал имя IPC счетчика и чтобы у каждого были соответствующие разрещения на доступ к объектам IPC (области разделяемой памяти и семафору).

В листинге 13.6 приведен текст программы-сервера, которая создает объект разделяемой памяти, затем создает и инициализирует семафор, после чего завер-щает работу.

Листинг 13.6. Программа, создающая и инициализирующая объект разделяемой памяти и семафор

pxshtti/serverl.c

1 finclude unpipc.h

2 struct shttistruct { /* структура, помещаемая в разделяемую память */

3 int count:

4 }:

5 sem t *mutex: /* указатель на именованный семафор */

6 int

7 mainCint argc. char **argv)

9 int fd:

10 struct shmstruct *ptr:

11 if Cargc != 3)

12 err quite usage: serverl <shmname> <semname> ):

13 shm unlink(Px ipc name(argv[l])): /* ошибки игнорируются */

14 /* создание shm. установка размера, отображение, закрытие дескриптора */

15 fd - Shm open(Px ipc name(argv[l]). 0 RDWR 0 CREAT OJXCL. FILE MODE):

16 FtruncateCfd. sizeofCstruct shmstruct)):

17 ptr = MmapCNULL. sizeofCstruct shmstruct). PROT READ PROT WRITE,

18 MAP SHARED. fd. 0):

19 CloseCfd):

20 sem unlinkCPx ipc nameCargv[2])): /* игнорируем ошибку */

21 mutex = Sem openCPxjpc nameCargv[2]). 0 CREAT OJXCL. FILE MODE. 1):

22 Sem closeCmutex):

23 exitCO):

24 }

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

13-19 Программа начинает работу с вызова shni unlink, на тот случай, если объект разделяемой памяти еще существует, а затем делается вызов shni open, создающий



этот объект. Его размер устанавливается равным размеру структуры shmstruct вызовом ftruncate, а затем mmap отображает объект в наше адресное пространство. После этого дескриптор объекта закрывается.

Создание и инициализация семафора

20-22 Сначала мы вызываем sem unl i nl<, на тот случай, если семафор еще существует. Затем делается вызов sem open для создания именованного семафора и инициализации его единицей. Этот семафор будет использоваться в качестве взаимного исключения всеми процессами, которые будут обращаться к объекту разделяемой памяти. После выполнения этих операций семафор закрывается.

Завершение работы процесса

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

Нам приходится использовать разные имена для семафора и объекта разделяемой памяти. Нет никаких гарантий, что в данной реализации к именам Posix IPC будут добавляться какие-либо суффиксы или префиксы, указывающие тип объекта (очередь сообщений, семафор, разделяемая память). Мы видели, что в Solaris эти типы имен имеют префиксы .MQ, .SEM и .SHM, но в Digital Unix они префиксов не имеют.

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

Листинг 13.7. Программа, увеличивающая значение счетчика в разделяемой памяти

pxsfitti/clientl.c

1 finclude unpipcli

2 struct shmstruct { /* структура, помещаемая в разделяемую память */

3 i nt count;

4 }:

5 sem t *mutex: /* указатель на именованный семафор */

6 int

7 mainCint argc. char **argv)

9 int fd. i, nloop:

10 pid t pid;

11 struct shmstruct *ptr;

12 if (argc != 4)

13 err quit( usage; clientl <shmname> <semname> <floops> );

14 nloop = atoi(argv[3]):

15 fd = Shm open(PxJpc name(argv[l]). OJDWR. FILE MODE);

16 ptr = Mmap(NULL. sizeof(struct shmstruct). PROTJEAD PROT WRITE,

17 MAPJHARED. fd. 0):

18 Close(fd):

19 mutex = Sem open(PxJpc name(argv[2]). 0);



20 pid = getpidO;

21 for (i = 0; i < nloop; i++) {

22 Setti wait(ttiutex):

23 printfCpid ld: %d\n . (long) pid. ptr->count++);

24 Setti post(ttiutex):

25 }

26 exit(O);

27 }

Открытие области разделяемой памяти

15-18 Вызов shni open открывает объект разделяемой памяти, который должен уже существовать (поскольку не указан флаг 0 CREAT). Память отображается в адресное пространство процесса вызовом mmap, после чего дескриптор закрывается,

Открытие семафора

19 Открываем именованный семафор.

Блокирование семафора и увеличение счетчика

20-26 Параметр командной строки позволяет указать количество увеличений счетчика, Каждый раз мы выводим предыдущее значение счетчика вместе с идентификатором процесса, поскольку одновременно работают несколько экземпляров программы.

Запустим сначала сервер, а затем три экземпляра программы-клиента в фоновом режиме.

Solaris % server shml semi

Solaris % clientl shml semi 10000 & clientl shml semi 10000 & clientl shml semi 10000&

интерпретатор выводит идентификаторы процессов

и этот процесс запускается первым

процесс 17977 продолжает работу

ядро переключается между процессами процесс 17976 продолжает работу

ядро переключается между процессами процесс 17978 продолжает работу

ядро переключается между процессами т. д.

последнее выводимое значение. Оно оказывается правильным.

13.6. Отправка сообщений на сервер

Изменим наще рещение задачи производителей и потребителей следующим образом. Сначала запускается сервер, создающий объект разделяемой памяти, в который клиенты записывают свои сообщения. Сервер просто выводит содержимое

[2] 17976

[3] 17977

[4] 17978

pid 17977:

pid 17977:

pid 17977;

pid 17976;

pid 17976;

pid 17978;

pid 17978;

pid 17977;

pid 17977;

29997

pid 17977;

29999



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.
Копирование материалов разрешено исключительно при условии цититирования.