Категории
Самые читаемые
onlinekniga.com » Компьютеры и Интернет » Программирование » UNIX: взаимодействие процессов - Уильям Стивенс

UNIX: взаимодействие процессов - Уильям Стивенс

Читать онлайн UNIX: взаимодействие процессов - Уильям Стивенс

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 71 72 73 74 75 76 77 78 79 ... 128
Перейти на страницу:

51     /*

52      До этого в наборе было semmsl элементов,

53      но теперь мы уменьшаем количество элементов на 1 и смотрим.

54      не получится ли создать семафор

55     */

56     for (j = semmsl-1; j > 0; j--) {

57      sid[1] = semget(IPC_PRIVATE, j, SVSEM_MODE | IPC_CREAT);

58      if (sid[i] != –1) {

59       semmns += j;

60       printf("max of %d semaphoresn", semmns);

61       Semctl(sid[i], 0, IPC_RMID);

62       goto done;

63      }

64     }

65     err_quit("j reached 0, semmns = %d", semmns);

66    }

67    semmns += semmsl;

68   }

69   printf("max of %d semaphoresn", semns);

70  done:

71   for (j = 0; j < i; j++)

72    Semctl(sid[j], 0, IPC_RMID);

73   /* определяем количество операций за вызов semop() */

74   semid = Semget(IPC_PRIVATE, semmsl, SVSEM_MODE | IPC_CREAT);

75   for (i = 1; i <= MAX_NOPS; i++) {

76    ops[i-1].sem_num = i-1;

77    ops[i-1].sem_op = 1;

78    ops[i-1].sem_flg = 0;

79    if (semop(semid, ops, i) += –1) {

80     if (errno != E2BIG)

81      err_sys("expected E2BIG from semop");

82     semopn = i-1;

83     printf("max of %d operations per semop()n", semopn);

84     break;

85    }

86   }

87   Semctl(semid, 0, IPC_RMID);

88   /* определение максимального значения semadj */

89   /* создание одного набора с одним семафором */

90   semid = Semget(IPC_PRIVATE, 1, SVSEM_MODE | IPC_CREAT);

91   arg.val = semvmx;

92   Semctl(semid, 0, SETVAL, arg); /* устанавливаем значение на максимум */

93   for (i = semvmx-1; i > 0; i--) {

94    ops[0].sem_num = 0;

95    ops[0].sem_op = –i;

96    ops[0].sem_flg = SEM_UNDO;

97    if (semop(semid, ops, 1) != –1) {

98     semaem = i;

99     printf("max value of adjust-on-exit = %dn", semaem);

100    break;

101   }

102  }

103  Semctl(semid, 0, IPC_RMID);

104  /* определение максимального количества структур UNDO */

105  /* создаем один набор с одним семафором и инициализируем нулем */

106  semid = Semget(IPC_PRIVATE, 1, SVSEM_MODE | IPC_CREAT);

107  arg.val = 0;

108  Semctl(semid, 0, SETVAL, arg); /* установка значения семафора в 0 */

109  Pipe(pipefd);

110  child = Malloc(MAX_NPROC * sizeof(pid_t));

111  for (i = 0; i < MAX_NPROC; i++) {

112   if ((child[i] = fork()) == –1) {

113    semmnu = i – 1;

114    printf("fork failed, semmnu at least %dn", semmnu);

115    break;

116   } else if (child[i] == 0) {

117    ops[0].sem_num = 0; /* дочерний процесс вызывает semop() */

118    ops[0].sem_op = 1;

119    ops[0].sem_flg = SEM_UNDO;

120    j = semop(semid, ops, 1); /* 0 в случае успешного завершения. –1 – в случае ошибки */

121    Write(pipefd[1], &j, sizeof(j));

122    sleep(30); /* ожидает завершения родительским процессом */

123    exit(0); /* на всякий случай */

124   }

125   /* родительский процесс считывает результат вызова semop() */

126   Read(pipefd[0], &j, sizeof(j));

127   if (j == –1) {

128    semmnu = i;

129    printf("max # undo structures = %dn", semmnu);

130    break;

131   }

132  }

133  Semctl(semid, 0, IPC_RMID);

134  for (j = 0; j <= i && child[j] > 0; j++)

135   Kill(child[j], SIGINT);

136  /* определение максимального количества записей корректировки на процесс */

137  /* создание одного набора с максимальным количеством семафоров */

138  semid = Semget(IPC_PRIVATE, semmsl, SVSEM_MODE | IPC_CREAT);

139  for (i = 0; i < semmsl; i++) {

140   arg.val = 0;

141   Semctl(semid, i, SETVAL, arg); /* установка значения семафора в 0 */

142   ops[i].sem_num = i;

143   ops[i].sem_op = 1; /* добавляем 1 к значению семафора */

144   ops[i].sem_flg = SEM_UNDO;

145   if (semop(semid, ops, i+1) == –1) {

146    semume = i;

147    printf("max # undo entries per process = %dn", semume);

148    break;

149   }

150  }

151  Semctl(semid, 0, IPC_RMID);

152  exit(0);

153 }

11.8. Резюме

У семафоров System V имеются следующие отличия от семафоров Posix:

1. Семафоры System V представляют собой набор значений. Последовательность операций над набором семафоров либо выполняется целиком, либо не выполняется вовсе.

2. К любому элементу набора семафоров могут быть применены три операции: проверка на нулевое значение, добавление некоторого значения к текущему и вычитание некоторого значения из текущего (в предположении, что значение остается неотрицательным). Для семафоров Posix определены только операции увеличения и уменьшения значения семафора на 1 (в предположении, что значение остается неотрицательным).

3. Создание семафора System V имеет некоторую особенность, заключающуюся в необходимости выполнения двух вызовов для создания и инициализации семафора, что может привести к ситуации гонок.

4. Семафоры System V предоставляют возможность отмены операции с ними (undo) после завершения работы процесса.

Упражнения

1. Листинг 6.6 представлял собой измененный вариант листинга 6.4, в котором программа принимала идентификатор очереди вместо полного имени файла. Мы продемонстрировали, что для получения доступа к очереди System V достаточно знать только ее идентификатор (предполагается наличие достаточных разрешений). Проделайте аналогичные изменения с программой в листинге 11.5 и посмотрите, верно ли вышесказанное для семафоров System V.

2. Что произойдет с программой в листинге 11.6, если файл LOCK_PATH не будет существовать?

ЧАСТЬ 4

РАЗДЕЛЯЕМАЯ ПАМЯТЬ

ГЛАВА 12

Введение в разделяемую память

12.1. Введение

Разделяемая память является наиболее быстрым средством межпроцессного взаимодействия. После отображения области памяти в адресное пространство процессов, совместно ее использующих, для передачи данных между процессами больше не требуется участие ядра. Обычно, однако, требуется некоторая форма синхронизации процессов, помещающих данные в разделяемую память и считывающих ее оттуда. В части 3 мы обсуждали различные средства синхронизации: взаимные исключения, условные переменные, блокировки чтения-записи, блокировки записей и семафоры.

ПРИМЕЧАНИЕ

Говоря «не требуется участие ядра», мы подразумеваем, что процессы не делают системных вызовов для передачи данных. Очевидно, что все равно именно ядро обеспечивает отображение памяти, позволяющее процессам совместно ею пользоваться, и затем обслуживает эту память (обрабатывает сбои страниц и т. п.).

Рассмотрим по шагам работу программы копирования файла типа клиент-сервер, которую мы использовали в качестве примера для иллюстрации различных способов передачи сообщений (рис. 4.1).

■ Сервер считывает данные из входного файла. Данные из файла считываются ядром в свою память, а затем копируются из ядра в память процесса.

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

ПРИМЕЧАНИЕ

Мы говорим «обычно», поскольку очереди сообщений Posix могут быть реализованы через отображение файла в память (функцию mmap мы опишем в этой главе), как мы показали в разделе 5.8 и в решении упражнения 12.2. На рис. 12.1 мы предполагаем, что очереди сообщений Posix реализованы в ядре, что также возможно. Но именованные и неименованные каналы и очереди сообщений System V требуют копирования данных из процесса в ядро вызовом write или msgsnd или копирования данных из ядра процессу вызовом read или msgrcv. 

■ Клиент считывает данные из канала IPC, что обычно требует их копирования из ядра в пространство процесса.

■ Наконец, данные копируются из буфера клиента (второй аргумент вызова write) в выходной файл.

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

Рис. 12.1. Передача содержимого файла от сервера к клиенту

Недостатком этих форм IPC — именованных и неименованных каналов — является то, что для передачи между процессами информация должна пройти через ядро.

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

1 ... 71 72 73 74 75 76 77 78 79 ... 128
Перейти на страницу:
На этой странице вы можете бесплатно читать книгу UNIX: взаимодействие процессов - Уильям Стивенс.
Комментарии