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

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 62 63 64 65 66 67 68 69 70 ... 128

38-42 Если мы создали семафор, его нужно проинициализировать, записав в канал FIFO value байтов. Если указанное при вызове значение value превышает определенное реализацией ограничение PIPE_BUF, вызов write после переполнения FIFO вернет ошибку с кодом EAGAIN.

Функция sem_close

Текст функции sem_close приведен в листинге 10.23.

11-15 Мы закрываем оба дескриптора и освобождаем память, выделенную под тип sem_t.

Листинг 10.23. Функция sem_close

//my_pxsem_fifo/sem_close.с

1  #include "unpipc.h"

2  #include "semaphore.h"

3  int

4  mysem_close(mysem_t *sem)

5  {

6   if (sem->sem_magic != SEM_MAGIC) {

7    errno = EINVAL;

8    return(-1);

9   }

10  sem->sem_magic = 0; /* чтобы семафор нельзя было больше использовать */

11  if (close(sem->sem_fd[0]) == –1 || close(sem->sem_fd[1]) == –1) {

12   free(sem);

13   return(-1);

14  }

15  free(sem);

16  return(0);

17 }

Функция sem_unlink

Функция sem_unlink, текст которой приведен в листинге 10.24, удаляет из файловой системы наш семафор. Она просто вызывает unlink.

Листинг 10.24. Функция sem_unlink

//my_pxsem_fifo/sem_unlink. с

1 #include "unpipc.h"

2 #include "semaphore.h"

3 int

4 mysem_unlink(const char *pathname)

5 {

6  return(unlink(pathname));

7 }

Функция sem_post

В листинге 10.25 приведен текст функции sem_post, которая увеличивает значение семафора.

11-12 Мы записываем один байт в FIFO. Если канал был пуст, это приведет к возобновлению выполнения всех процессов, заблокированных в вызове read для этого канала.

Листинг 10.25. Функция sem_post

//my_pxsem_fifo/sem_post.с

1  #include "unpipc.h"

2  #include "semaphore.h"

3  int

4  mysem_post(mysem_t *sem)

5  {

6   char c;

7   if (sem->sem_magic != SEM_MAGIC) {

8    errno = EINVAL;

9    return(-1);

10  }

11  if (write(sem->sem_fd[1], &c, 1) == 1)

12   return(0);

13  return(-1);

14 }

Функция sem_wait

Последняя функция для работы с именованными семафорами Posix — sem_wait. Ее текст приведен в листинге 10.26.

Листинг 10.26. Функция sem_wait

//my_pxsem_fifo/sem_wait.с

1  #include "unpipc.h"

2  #include "semaphore.h"

3  int

4  mysem_wait(mysem_t *sem)

5  {

6   char c;

7   if (sem->sem_magic != SEM_MAGIC) {

8    errno = EINVAL;

9    return(-1);

10  }

11  if (read(sem->sem_fd[0], &c, 1) == 1)

12   return(0);

13  return(-1);

14 } 

11-12 Мы считываем 1 байт из канала FIFO, причем работа приостанавливается, если канал пуст.

Мы еще не реализовали функцию sem_trywait, но это можно сделать, установив флаг отключения блокировки для канала и используя обычный вызов read. Мы также не реализовали функцию sem_getvalue. В некоторых реализациях при вызове функции stat или fstat возвращается количество байтов в именованном или неименованном канале, причем оно помещается в поле st_size структуры stat. Однако это не гарантируется стандартом Posix и, следовательно, не обязательно будет работать в других системах. Пример реализации этих двух функций для работы с семафорами Posix приведен в следующем разделе.

10.15. Реализация с помощью отображения в память

Теперь займемся реализацией именованных семафоров Posix с помощью отображаемых в память файлов вместе со взаимными исключениями и условными переменными Posix. Реализация, аналогичная данной, приведена в разделе В.11.3 Обоснования стандарта IEEE 1996 [8].

ПРИМЕЧАНИЕ

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

Прежде всего приведем текст нашего заголовочного файла semaphore.h (листинг 10.27), в котором определяется фундаментальный тип sem_t.

Тип sem_t

1-7 Структура данных семафора содержит взаимное исключение, условную переменную и беззнаковое целое, в котором хранится текущее значение семафора. Как уже говорилось в связи с листингом 10.21, поле sem_magiс получает значение SEM_MAGIC при инициализации структуры.

Листинг 10.27. Заголовочный файл semaphore.h

//my_pxsem_mmap/semaphore.h

1  /* фундаментальный тип */

2  typedef struct {

3   pthread_mutex_t sem_mutex; /* блокируется при проверке и изменении значения семафора */

4   pthread_cond_t sem_cond; /* при изменении нулевого значения */

5   unsigned int sem_count; /* значение семафора */

6   int sem_magic; /* магическое значение, если семафор открыт */

7  } mysem_t;

8  #define SEM_MAGIC 0x67458923

9  #ifdef SEM_FAILED

10 #undef SEM_FAILED

11 #define SEM_FAILED ((mysem_t *)(-1)) /* чтобы избежать предупреждений компилятора */

12 #endif

Функция sem_open

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

Листинг 10.28. Функция sem_open: первая половина

//my_pxsem_mmap/sem_open.с

1  #include "unpipc.h"

2  #include "semaphore.h"

3  #include <stdarg.h> /* для списков аргументов переменной длины */

4  #define MAX_TRIES 10 /* количество попыток инициализации */

5  mysem_t *

6  mysem_open(const char *pathname, int oflag, …)

7  {

8   int fd, i, created, save_errno;

9   mode_t mode;

10  va_list ap;

11  mysem_t *sem, seminit;

12  struct stat statbuff;

13  unsigned int value;

14  pthread_mutexattr_t mattr;

15  pthread_condattr_t cattr;

16  created = 0;

17  sem = MAP_FAILED; /* [sic] */

18 again:

19  if (oflag & O_CREAT) {

20   va_start(ap, oflag); /* ар инициализируется последним явно указанным аргументом */

21   mode = va_arg(ap, va_mode_t) & ~S_IXUSR;

22   value = va_arg(ap, unsigned int);

23   va_end(ap);

24   /* открываем с указанием флага O_EXCL и установкой бита user-execute */

25   fd = open(pathname, oflag | O_EXCL | O_RDWR, mode | S_IXUSR);

26   if (fd < 0) {

27    if (errno == EEXIST && (oflag & O_EXCL) == 0)

28     goto exists; /* уже существует. OK */

29    else

30     return(SEM_FAILED);

31   }

32   created = 1;

33   /* кто создает файл, тот его и инициализирует */

34   /* установка размера файла */

35   bzero(&seminit, sizeof(seminit));

36   if (write(fd, &seminit, sizeof(seminit)) != sizeof(seminit))

37    goto err;

38   /* отображение файла в память */

39   sem = mmap(NULL, sizeof(mysem_t), PROT_READ | PROT_WRITE,

40    MAP_SHARED, fd, 0);

41   if (sem == MAP_FAILED)

42    goto err;

43   /* инициализация взаимного исключения, условной переменной, значения семафора */

44   if ((i = pthread_mutexattr_init(&mattr)) != 0)

45    goto pthreaderr;

46   pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);

47   i = pthread_mutex_init(&sem->sem_mutex, &mattr);

48   pthread_mutexattr_destroy(&mattr); /* не забыть удалить */

49   if (i != 0)

50    goto pthreaderr;

51   if ((i = pthread_condattr_init(&cattr)) != 0)

52    goto pthreaderr;

53   pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);

54   i = pthread_cond_init(&sem->sem_cond, &cattr);

55   pthread_condattr_destroy(&cattr); /* не забыть удалить */

56   if (i != 0)

57    goto pthreaderr;

58   if ((sem->sem_count = value) > sysconf(_SC_SEM_VALUE_MAX)) {

59    errno = EINVAL;

60    goto err;

61   }

62   /* инициализация завершена, снимаем бит user-execute */

63   if (fchmod(fd, mode) == –1)

64    goto err;

65   close(fd);

66   sem->sem_magic = SEM_MAGIC;

67   return(sem);

68  }

Работа со списком аргументов переменной длины

19-23 Если при вызове функции указан флаг O_CREAT, мы должны принять четыре аргумента, а не два. Работа со списком аргументов переменной длины с помощью типа va_mode_t уже обсуждалась в связи с листингом 5.17, где мы использовали метод, аналогичный примененному здесь. Мы сбрасываем бит user-execute переменной mode (S_IXUSR) по причинам, которые вскоре будут раскрыты. Создается файл с указанным именем, и для него устанавливается бит user-execute.

Создание нового семафора и обработка потенциальной ситуации гонок

24-32 Если бы при указании флага O_CREAT мы просто открывали файл, отображали в память его содержимое и инициализировали поля структуры sem_t, у нас возникла бы ситуация гонок. Эта ситуация также уже обсуждалась в связи с листингом 5.17, и там мы воспользовались тем же методом, что и сейчас. Такая же ситуация гонок встретится нам, когда мы будем разбираться с листингом 10.37.

1 ... 62 63 64 65 66 67 68 69 70 ... 128
На этом сайте Вы можете читать книги онлайн бесплатно русская версия UNIX: взаимодействие процессов - Уильям Стивенс.

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