Семафор с индексом 1 управляет доступом к файлу устройства, обозначенному переменной среды PRINTER1. Семафор с индексом 2 управляет устройством, на которое ссылается PRINTER2.

Первые четыре буквы имени команды определят, должен вывод идти на принтер, связанный с PRINTER1 или с PRINTER2. Если имя команды начинается с line, должен быть использо­ван PRINTER1. Если оно начинается с lase, нужно использовать PRINTER2.


Создание набора семафоров - Пример

Этот пример использует набор семафоров для управления всеми принтерами, трактуемыми как общий ресурс печати. Этот код показывает, как создать и инициализировать набор из бо­лее чем одного семафора.

Эта программа использует следующий файл заголовка:

printer. h

1  #define  DUMMY  0

2  #define  NUMPR  2/* number of printers */

3  #define  ACQUIRE  -1

4  #define  RELEASE  1

Фрагмент программы работает так:

15  Объявление массива, содержащего инициализационные значения всех се­мафоров в наборе.

...  Переменные среды PRINTER1 и PRINTER2 содержат имена "принтеров", ассоциированных с индексами 1 и 2 набора семафоров. Эти "принтеры" могут быть как файлами, так и устройствами.

31  Формирование ключа  на основании  имени программы и буквы s. Так как два имени программы laserprnt и lineprnt представляют собой ссылки на один и тот же файл, ftok(3), используя эти имена в качестве параметров, выдает одно и то же устройство и номер инода.

32-35  Здесь  создается  набор  из  NUMPR + 1  семафоров.  Дополнительный се­мафор с индексом 0 управляет ресурсом печати в целом.

НЕ нашли? Не то? Что вы ищете?

45-54  Первый семафор в наборе инициализируется количеством принтеров в об­щем ресурсе печати. Остальные семафоры инициализируются в 1.  Заметьте, что  второй аргумент  semctl(2) не используется.

Файл: printer. c

  СОЗДАНИЕ НАБОРА СЕМАФОРОВ - ПРИМЕР

1 #include <stdlib. h>

2 #include <string. h>

3 #include <unistd. h>

4 #include <fcntl. h>

5 #include <sys/types. h>

6 #include <sys/ipc. h>

7 #include <sys/sem. h>

8 #include <stdio. h>

9 #include "printer. h"

10

11 main(int argc, char *argv[])

12 {

...

14  key_t ipckey;

15  ushort initial[NUMPR + 1], prntnum;

...

31  ipckey = ftok(argv[0], 's');

32  if ((semid = semget(ipckey, NUMPR + 1,

33  IPC_CREAT | IPC_EXCL | 0666)) != -1) {

34  creator = 1;

35  }

...

45  if(creator) { /* initialize semaphore set */

46  initial[0] = NUMPR;

47  for (n = 1; n <= NUMPR; n++)

48  initial[n] = 1;

49  if(semctl(semid, DUMMY, SETALL, initial) == -1) {

50  sprintf(errmsg,"%s - SETALL", argv[0]);

51  perror(errmsg);

52  exit(3);

53  }

54  }

...


Операции над набором семафоров — Пример (продолжение)

Код, приведенный в этом примере, представляет собой часть той же программы, что и пре­дыдущий пример. Он демонстрирует, как оперировать с двумя семафорами в наборе од­новременно.

Фрагмент программы работает так:

...  Имя  команды  определяет  принтер,  который  нужно использовать.

56-61  Две командные структуры установлены так, чтобы уменьшить на 1 первый семафор и семафор, связанный с принтером с номером prnnum. Заметьте, что исполь­зуется флаг SEM_UNDO. Вспомните, что номер семафора, над которым должна быть выполнена операция, содержится в командной структуре.

62-66  Здесь  выполняется  операция  над  двумя  семафорами одновременно. Эта операция захватит принтер, который должен быть использован. Другой процесс, ис­полняющий этот же код, будет заблокирован до тех пор, пока значение сема­фора не увеличится.

79-85  Командные структуры для обоих семафоров изменены так, чтобы увеличить значение семафоров на 1. Оба семафора изменяются "одновременно", т. е. ни один другой процесс не получит управления в промежутке между их изменениями.

Эта программа демонстрируется так:

$ ln printer lineprntr

$ ln printer laseprntr

$ PRINTER1=/dev/tty05

$ PRINTER2=/tmp/xyz

$ export PRINTER1 PRINTER2

$ lineprntr data & lineprntr data & wait

3909

3910

  1ABCDEFGHIJKLMNOPQRSTUVWXYZ

  2ABCDEFGHIJKLMNOPQRSTUVWXYZ

  3ABCDEFGHIJKLMNOPQRSTUVWXYZ

  4ABCDEFGHIJKLMNOPQRSTUVWXYZ

  1ABCDEFGHIJKLMNOPQRSTUVWXYZ

  2ABCDEFGHIJKLMNOPQRSTUVWXYZ

  3ABCDEFGHIJKLMNOPQRSTUVWXYZ

  4ABCDEFGHIJKLMNOPQRSTUVWXYZ

$ ipcs - s

IPC status from /dev/kmem as of Tue Mar  3 11:18:53 1987

T  ID  KEY  MODE  OWNER  GROUP

Semaphores:

s  100 0x7304001a --ra-ra-ra-  jeg  unixc

$ ipcrm - s 100

Файл: printer. c

  ОПЕРАЦИИ НАД НАБОРОМ СЕМАФОРОВ - ПРИМЕР

1  #include <stdlib. h>

2  #include <string. h>

3  #include <unistd. h>

4  #include <fcntl. h>

5  #include <sys/types. h>

6  #include <sys/ipc. h>

7  #include <sys/sem. h>

8  #include <stdio. h>

9  #include "printer. h"

10

11  main(int argc, char *argv[])

12  {

...

17  struct sembuf operation[2];

...

56  operation[1].sem_num = prntnum;

57  operation[1].sem_op = ACQUIRE;

58  operation[1].sem_flg = SEM_UNDO;

59  operation[0].sem_num = 0;

60  operation[0].sem_op = ACQUIRE;

61  operation[0].sem_flg = SEM_UNDO;

62  if(semop(semid, operation, 2) == -1) {

63  sprintf(errmsg,"%s - ACQUIRE",argv[0]);

64  perror(errmsg);

65  exit(4);

66  }

...

79  operation[1].sem_op = RELEASE;

80  operation[0].sem_op = RELEASE;

81  if(semop(semid, operation, 2) == -1) {

82  sprintf(errmsg,"%s - RELEASE",argv[0]);

83  perror(errmsg);

84  exit(7);

85  }

...

87  }


Разделяемая память

Разделяемая память System V IPC позволяет двум или более процессам разделять память и, следовательно, находящиеся в ней данные. Это достигается помещением в виртуальное ад­ресное пространство процессов одной и той же физической памяти.

Того же эффекта можно достичь, отобразив в память при помощи mmap(2) доступный на за­пись файл в режиме MAP_SHARED. Как и в случае mmap(2), разделяемые сегменты не обя­зательно будут отображены на одни и те же адреса в разных процессах.

Главным практическим отличием разделяемой памяти System V IPC от mmap(2) является то, что для mmap(2) нужен файл, а память System V IPC ни к какому файлу не привязана. Кроме того, использование mmap(2) с флагом MAP_SHARED приводит к тому, что система синхро­низует содержимое памяти с диском, что может снизить общую производительность систе­мы. Если вам нужно сохранить содержимое разделяемой памяти после завершения работы всех процессов приложения, mmap(2) оказывается удобнее, но на практике такая потреб­ность возникает довольно редко. Поэтому разделяемая память System V IPC до сих пор ши­роко применяется многими приложениями.

В последние годы, разделяемая память вытесняется многопоточными программами. С опре­деленными оговорками, с точки зрения программиста, потоки можно рассматривать как про­цессы, у которых вся память разделяется.

Этот раздел показывает, как создавать и использовать сегмент разделяемой памяти. Это вы­полняется следующими системными вызовами.

.  shmget

.  shmat

.  shmdt

.  shmctl


Разделяемая память

Это средство IPC позволяет двум или более процессам разделять память.

Такая память используется для хранения данных, которые нужны нескольким процессам. Это могут быть поисковые таблицы, критерии правильности данных и т. д. Разделяемая па­мять представляет собой самый быстрый способ обмена данными между процессами.

Как правило, один процесс создает сегмент разделяемой памяти вызовом shmget(2) с флагом IPC_CREAT, отображает его в свое адресное пространство и инициализирует. Отображения разделяемого сегмента в адресное пространство процесса называют присоединением сегмен­та. Затем другие процессы могут присоединять этот сегмент и использовать его содержимое. Создатель задает права чтения/записи для хозяина/группы/других пользователей. Обычно сегмент удаляется тем же процессом, который создал его.

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

Через разделяемую память могут взаимодействовать неродственные процессы. Все, что нуж­но процессу для присоединения разделяемого сегмента, это соответствующие права доступа для своих идентификаторов пользователя и группы.

Когда сегмент больше не нужен процессу, он отсоединяет его вызовом shmdt(2). Если это не было сделано явным образом, это произойдет при завершении процесса (как по exit(2), так и по сигналу) или при exec(2) . Отсоединение разделяемой памяти похоже на закрытие файла. Отсоединение не удаляет разделяемый сегмент, оно только логически исключает этот сег­мент из виртуального пространства данных программы.

В отличие от остальных средств IPC, у разделяемой памяти происходит отложенное удале­ние. Вызов shmctl(2) с командой IPC_RMID приводит только к тому, что новые процессы не могут присоединиться к этому сегменту, но не к отсоединению этих сегментов у процессов, которые их используют. Запрос на удаление помечает сегмент, но само удаление происходит только когда количество присоединившихся процессов станет равно 0. Флаг ожидания уда­ления виден как D в выводе команды ipcs(1).

Родительский и порожденные процессы также могут использовать сегменты разделяемой па­мяти. После fork(2) порожденный процесс наследует присоединенные разделяемые сегмен­ты. Обычные сегменты памяти данных после fork(2) копируются при записи, а сегменты раз­деляемой памяти остаются общими, так что родитель и потомок видят изменения, вносимые другим процессом, и могут взаимодействовать через них. При этом, в родителе и в потомке сегмент будет отображен на одни и те же виртуальные адреса.

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9