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

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 55 56 57 58 59 60 61 62 63 ... 128

23 Мы вызываем sem_close, хотя, если бы мы не сделали этот вызов, семафор все равно закрылся бы автоматически при завершении процесса и ресурсы системы были бы высвобождены.

Программа semunlink

Программа в листинге 10.4 удаляет именованный семафор.

Листинг 10.4. Удаление именованного семафора

//pxsem/semunlink.c

1 #include "unpipc.h"

2 int

3 main(int argc, char **argv)

4 {

5  if (argc != 2)

6   err_quit("usage: semunlink <name>");

7  Sem_unlink(argv[1]);

8  exit(0);

9 }

Программа semgetvalue

В листинге 10.5 приведен текст простейшей программы, которая открывает указанный именованный семафор, получает его текущее значение и выводит его.

Листинг 10.5. Получение и вывод значения семафора

//pxsem/semgetvalue.с

1  #include "unpipc.h"

2  int

3  main(int argc, char **argv)

4  {

5   sem_t *sem;

6   int val;

7   if (argc != 2)

8    err_quit("usage: semgetvalue <name>");

9   sem = Sem_open(argv[1], 0);

10  Sem_getvalue(sem, &val);

11  printf("value = %dn", val);

12  exit(0);

13 }

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

9 Семафор, который мы открываем, должен быть заранее создан другой программой. Вторым аргументом sem_open будет 0: мы не указываем флаг O_CREAT и нам не нужно задавать никаких других параметров открытия 0_ххх.

Программа semwait

Программа в листинге 10.6 открывает именованный семафор, вызывает semwait (которая приостанавливает выполнение процесса, если значение семафора меньше либо равно 0, а при положительном значении семафора уменьшает его на 1), получает и выводит значение семафора, а затем останавливает свою работу навсегда при вызове pause.

Листинг 10.6. Ожидание изменения значения семафора и вывод нового значения

//pxsem/semwait.c

1  #include "unpipc.h"

2  int

3  main(int argc, char **argv)

4  {

5   sem_t *sem;

6   int val;

7   if (argc != 2)

8    err_quit("usage: semwait <name>");

9   sem = Sem_open(argv[1], 0);

10  Sem_wait(sem);

11  Sem_getvalue(sem, &val);

12  printf("pid %ld has semaphore, value = %dn", (long) getpid(), val);

13  pause(); /* блокируется, пока не будет удален */

14  exit(0);

15 }

Программа sempost

В листинге 10.7 приведена программа, которая выполняет операцию post для указанного семафора (то есть увеличивает его значение на 1), а затем получает значение этого семафора и выводит его.

Листинг 10.7. Увеличение значения семафора

//pxsem/sempost.c

1  #include "unpipc.h"

2  int

3  main(int argc, char **argv)

4  {

5   sem_t *sem;

6   int val;

7   if (argc != 2)

8    err_quit("usage: sempost <name>");

9   sem = Sem_open(argv[1], 0);

10  Sem_post(sem);

11  Sem_getvalue(sem, &val);

12  printf("value = %dn", val);

13  exit(0);

14 }

Примеры

Для начала мы создадим именованный семафор в Digital Unix 4.0B и выведем его значение, устанавливаемое по умолчанию при инициализации:

alpha % semcreate /tmp/test1

alpha % ls-l /tmp/test1

-rw-r--r-- 1 rstevens system 264 Nov 13 08:51 /tmp/test1

alpha %semgetvalue /tmp/test1

value = 1

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

Теперь подождем изменения семафора и прервем работу программы, установившей блокировку:

alpha % semwait /tmp/test1

pid 9702 has semaphore, value = 0 значение после возврата из sem_wait

^?                                клавиша прерывания работы в нашей системе

alpha % semgetvalue /tmp/test1

value = 0                         значение остается нулевым

Приведенный пример иллюстрирует упомянутые ранее особенности. Во-первых, значение семафора обладает живучестью ядра. Значение 1, установленное при создании семафора, хранится в ядре даже тогда, когда ни одна программа не пользуется этим семафором. Во-вторых, при выходе из программы semwait, заблокировавшей семафор, значение его не изменяется, то есть ресурс остается заблокированным. Это отличает семафоры от блокировок fcntl, описанных в главе 9, которые снимались автоматически при завершении работы процесса.

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

alpha % semgetvalue /tmp/test1

value = 0                          это значение сохранилось с конца предыдущего примера

alpha % semwait /tmp/test1 &      запуск в фоновом режиме

[1] 9718                           блокируется в ожидании изменения значения семафора

alpha % semgetvalue /tmp/test1

value = –1                         один процесс ожидает изменения семафора

alpha % semwait /tmp/test1 &       запуск еще одного процесса в фоновом режиме

[2] 9727                           он также блокируется

alpha % semgetvalue /tmp/test1

value = –2                         два процесса ожидают изменения семафора

alpha % sempost /tmp/test1

value = –1                         значение после возвращенияиз sem_post

pid 9718 has semaphore, value = –1 вывод программы semwait

alpha % sempost /tmp/test1

value = 0

pid 9727 has semaphore, value = 0  вывод программы semwait

При первом вызове sem_post значение семафора изменилось с –2 на –1 и один из процессов, ожидавших изменения значения семафора, был разблокирован.

Выполним те же действия в Solaris 2.6, обращая внимание на различия в реализации:

solaris % semcreate /test2

solaris % ls –l /tmp/.*test2*

-rw-r--r-- 1 rstevens other1 48 Nov 13 09:11 /tmp/.SEMDtest2

–rw-rw-rw– 1 rstevens other1  0 Nov 13 09:11 /tmp/.SEMLtest2

solaris % semgetvalue /test2

value = 1

Аналогично очередям сообщений Posix файлы создаются в каталоге /tmp, причем указываемое при вызове имя становится суффиксом имен файлов. Разрешения первого файла соответствуют указанным в вызове sem_open, а второй файл, как можно предположить, используется для блокировки доступа.

Проверим, что ядро не осуществляет автоматического увеличения значения семафора при завершении работы процесса, установившего блокировку:

solaris % semwait /test2

pid 4133 has semaphore, value = 0

^? нажимаем клавишу прерывания выполнения

solaris % semgetvalue /test2

value = 0

Посмотрим теперь, как меняется значение семафора в этой реализации при появлении новых процессов, ожидающих изменения значения семафора:

solaris % semgetvalue /test2

value = 0                       значение сохранилось с конца предыдущего примера

solaris % semwait /test2&       запуск в фоновом режиме

[1] 4257                        программа блокируется

solaris % semgetvalue /test2

value = 0                        в этой реализации отрицательные значения не используются

solaris % semwait /test2&        еще один фоновый процесс

[2] 4263

solaris % semgetvalue /test2

value 0                          и для двух ожидающих процессов значение остается нулевым

solaris % sempost /test2          выполняем операцию post

pid 4257 has semaphore, value = 0 вывод программы semwait

value = 0

solaris % sempost /test2

pid 4263 has semaphore, value = 0 вывод программы semwait

value = 0

Можно заметить отличие по сравнению с результатами выполнения той же последовательности команд в Digital Unix 4.0B: после изменения значения семафора управление сразу же передается ожидающему изменения семафора процессу.

10.6. Задача производителей и потребителей

В разделе 7.3 мы описали суть задачи производителей и потребителей и привели несколько возможных ее решений, в которых несколько потоков-производителей заполняли массив, который обрабатывался одним потоком-потребителем.

1 ... 55 56 57 58 59 60 61 62 63 ... 128
На этом сайте Вы можете читать книги онлайн бесплатно русская версия UNIX: взаимодействие процессов - Уильям Стивенс.

Оставить комментарий