Литмир - Электронная Библиотека
Содержание  
A
A

<b>}</b>

В большинстве версий ОС Linux определение объединения

semun
включено в заголовочный файл (обычно sem.h), несмотря на то, что стандарт X/Open настаивает на том, что вы должны привести собственное объявление. Если вы поймете, что должны объявить его самостоятельно, проверьте, нет ли объявления этого объединения на страницах интерактивного справочного руководства, относящихся к функции
semctl
. Если вы найдете его, мы полагаем, что вы примените определение из вашего справочного руководства, даже если оно отличается от приведенного на страницах этой книги.

Существует множество разных значений параметра command, допустимых в функции

semctl
. Обычно применяются два из них, которые описаны далее. Более подробную информацию о функции
semctl
см. в интерактивном справочном руководстве.

Два часто используемых значения

command
таковы:

□ 

SETVAL
— применяется для инициализации семафора с заданным значением. Это значение передается как элемент
val
объединения
semun
. Такое действие необходимо для того, чтобы увеличить значение семафора перед первым его применением;

□ 

IPC_RMID
— применяется для удаления идентификатора семафора, когда он больше не нужен.

Функция

semctl
возвращает разные значения, зависящие от параметра
command
. Если значение команды —
IPC_RMID
, функция в случае успешного завершения вернет 0 и -1 в противном случае.

Применение семафоров

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

К счастью, большинство задач, нуждающихся в семафорах, можно решить, применяя единственный бинарный семафор — простейший тип семафора. В следующем примере (упражнение 14.1) вы используете полный программный интерфейс для создания очень простого интерфейса типа Р и V для бинарного семафора. Затем вы примените этот простенький интерфейс для демонстрации того, как функционируют семафоры.

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

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

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

Упражнение 14.1. Семафоры

1. После системных директив

#include
вы включаете файл semun.h. Он определяет объединение типа
semun
в соответствии со стандартом X/Open, если оно уже не описано в системном файле sys/sem.h. Далее следуют прототипы функций и глобальная переменная, расположенные перед входом в функцию
main
. В ней создается семафор с помощью вызова
semget
, который возвращает ID семафора. Если программа вызывается первый раз (т.е. вызывается с параметром и
argc &gt; 1
), выполняется вызов
set_semvalue
для инициализации семафора и переменной
op_char
присваивается значение
O
.

#include &lt;unistd.h&gt;

#include &lt;stdlib.h&gt;

#include &lt;stdio.h&gt;

#include &lt;sys/sem.h&gt;

#include &quot;semun.h&quot;

static int set_semvalue(void);

static void del_semvalue(void);

static int semaphore_p(void);

static int semaphore_v(void);

static int sem_id;

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

 int i;

 int pause_time;

 char op_char = 'О';

 srand((unsigned int)getpid());

 sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT);

 if (argc &gt;1) {

  if (!set_semvalue()) {

   fprintf(stderr, &quot;Failed to initialize semaphore\n&quot;);

   exit(EXIT_FAILURE);

  }

  op_char = 'X';

  sleep(2);

 }

2. Далее следует цикл, в котором 10 раз выполняется вход в критическую секцию и выход из нее. Вы сначала выполняете вызов функции

semaphore_p
, которая заставляет семафор ждать, когда эта программа будет готова войти в критическую секцию.

 for (i = 0; i &lt; 10; i++) {

  if (!semaphore_p()) exit(EXIT_FAILURE);

  printf(&quot;%c&quot;, op_char);

  fflush(stdout);

  pause_time = rand() % 3;

  sleep(pause_time);

  printf(&quot;%c&quot;, op_char);

  fflush(stdout);

3. После критической секции вы вызываете функцию

semaphore_v
, которая освобождает семафор перед повторным проходом цикла
for
после ожидания в течение случайного промежутка времени. После цикла выполняется вызов функции
del_semvalue
для очистки кода.

  if (!semaphore_v()) exit(EXIT_FAILURE);

  pause_time = rand() % 2;

  sleep(pause_time);

 }

 printf(&quot;\n%d - finished\n&quot;, getpid());

252
{"b":"285844","o":1}