Чтение онлайн

ЖАНРЫ

UNIX: взаимодействие процессов

Стивенс Уильям Ричард

Шрифт:

//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.

Установка размера файла
Поделиться с друзьями: