Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 [ 90 ] 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

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

44 if ( (1 - pthread mutexattr lnit(&mattr)) != 0)

45 goto pthreaderr;

46 pthread mutexattr setpshared(&mattr, PTHREAD PROCESS SHARED):

47 1 = pthread mutex 1n1t(&sem->sem mutex. &mattr):

48 pthread mutexattr destroy(&mattr)-. /* не забыть удалить */

49 if (i != 0)

50 goto pthreaderr:

51 if ( (i = pthread condattrjnit(&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 Если при вызове функции указан флаг 0 CREAT, мы должны принять четыре аргумента, а не два. Работа со списком аргументов переменной длины с помощью типа va mode t уже обсуждалась в связи с листингом 5.17, где мы использовали метод, аналогичный примененному здесь. Мы сбрасываем бит user-execute переменной mode (S IXUSR) по причинам, которые вскоре будут раскрыты. Создается файл с указанным именем, и для него устанавливается бит user-execute.

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

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

Установка размера файла

33-37 Мы устанавливаем размер созданного файла, записывая в него заполненную нулями структуру. Поскольку мы знаем, что только что созданный файл имеет размер О, для установки его размера мы вызываем именно write, но не ftruncate, потому что, как мы отмечаем в разделе 13.3, Posix не гарантирует, что ftruncate срабатывает при увеличении размера обычных файлов.



Отображение содержимого файла в память

38-42 Файл отображается в память вызовом mmap. Этот файл будет содержать текущее значение структуры типа sem t, хотя, поскольку мы только что отобразили файл в память, мы обращаемся к нему через указатель, возвращаемый mmap, и никогда не вызываем read или write.

Инициализация структуры sem t

43-57 Мы инициализируем три поля структуры sem t: взаимное исключение, условную переменную и значение семафора. Поскольку именованный семафор Posix может совместно использоваться всеми процессами с соответствующими правами, которым известно его имя, при инициализации взаимного исключения и условной переменной необходимо указать атрибут PTHREAD PROCESS SHARED. Чтобы осуществить это для взаимного исключения, нужно сначала проинициализировать атрибуты, вызвав pthread mutexattr init, затем установить атрибут совместного использования потоками, вызвав pthread mutexattr setpshared, а затем проинициализировать взаимное исключение вызовом pthread mutex init. Аналогичные действия придется выполнить и для условной переменной. Необходимо аккуратно уничтожать переменные, в которых хранятся атрибуты, при возникновении ошибок.

Инициализация значения семафора

58-61 Наконец мы помещаем в файл начальное значение семафора. Предварительно мы сравниваем его с максимально разрешенным значением семафора, которое может быть получено вызовом sysconf (раздел 10.13).

Сброс бита user-execute

62-67 После инициализации семафора мы сбрасываем бит user-execute. Это указывает на то, что семафор был успешно проинициализирован. Затем мы закрываем файл вызовом close, поскольку он уже был отображен в память и нам не нужно держать его открытым.

В листинге 10.29 приведен текст второй половины функции sem open. Здесь возникает ситуация гонок, обрабатываемая так же, как уже обсуждавшаяся в связи с листингом 5.19.

Листинг 10.29. Функция sem open: вторая половина

/ /my pxsem niiiap/sem open. с

69 exists:

70 if ( (fd = open(pathname. 0 RDWR)) < 0) {

71 if (errno =- ENOENT && (oflag & 0 CREAT))

72 goto again:

73 goto err:

74 }

75 sem = mmap(NULL. sizeof(mysem t). PROT READ PROT WRITE.

76 MAP SHARED. fd. 0):

77 if (sem MAPJAILED)

78 goto err:

79 /* удостоверимся, что инициализация завершена */

80 for (1 = 0: i < MAX TRIES: 1++) {



ПРИМЕЧАНИЕ

Теперь легко понять, почему в Posix.l сказано, что обращение к копиям семафора приводит к неопределенным результатам . Если именованный семафор реализован через отображение файла в память, он отображается в адресное пространство всех процессов, в которых он открыт. Это осуществляется функцией sem open для каждого процесса в отдельности. Изменения, сделанные одним процессом (например, изменение счетчика семафора), становятся доступны другим процессам через отображение в память. Если мы сделаем свою собственную копию структуры sem t, она уже не будет общей для всех процессов. Хотя нам и может показаться, что вызовы срабатывают (функции для работы с семафором не будут возвращать ошибок, по крайней мере до вызова sem close, которая не сможет отключить отображение для копии отображенного файла), с другими процессами мы при этом взаимодействовать не сможем. Однако заметьте (табл. 1.4), что области памяти с отображаемыми файлами передаются дочерним процессам при вызове fork, поэтому создание копии семафора ядром при порождении нового процесса проблем не вызовет.

81 if (stat(pathname. &statbuff) ~ -1) {

82 if (еггпо = ENOENT && (oflag & 0 CREAT)) {

83 close(fd):

84 goto again;

85 }

86 goto err;

87 }

88 if ((statbuff.st mode & SJXUSR) == 0) {

89 close(fd):

90 sem->sem mag1c = SEM MAGIC;

91 return(sem):

92 }

93 sleep(l);

94 }

95 errno = ETIMEDOUT;

96 goto err;

97 pthreaderr:

98 errno = i;

99 err:

100 /* не даем вызовам unlink и munmap изменить код errno */

101 save errno = errno:

102 if (created)

103 unlink(pathname):

104 if (sem != MAPJAILED)

105 munmap(sem. sizeof(mysem t)):

106 close(fd);

107 errno = save errno:

108 return(SEM FAILED):

109 }

Открытие существующего семафора

69-78 Здесь мы завершаем нашу работу, если либо не указан флаг 0 CREAT, либо он указан, но семафор уже существует. В том и в другом случае мы открываем существующий семафор. Мы открываем файл вызовом open для чтения и записи, а затем отображаем его содержимое в адресное пространство процесса вызовом гшар.



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 [ 90 ] 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.