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

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

Это называется зависанием программы (deadlock). Производитель ожидает освобождения семафора mutex, а потребитель не снимает с него блокировку, ожидая освобождения семафора nstored. Но производитель не может изменить nstored, пока он не получит семафор mutex. Это одна из проблем, которые часто возникают с семафорами: если в программе сделать ошибку, она будет работать неправильно.

ПРИМЕЧАНИЕ

Стандарт Posix позволяет функции sem wait обнаруживать зависание и возвращать ошибку EDEADLK, но ни одна из систем, использовавшихся для написания примеров (Digital Unix 4.0В и Solaris 2.6), не обнаружила ошибку в данном случае.

10.7. Блокирование файлов

Вернемся к задаче о порядковом номере из главы 9. Здесь мы напишем новые версии функций ту 1 оск и my unl оск, использующие именованные семафоры Posix. В листинге 10.10 приведен текст этих функций.

Листинг 10.10. Блокирование файла с помощью именованных семафоров Posix

lock/lockpxsem.c

1 finclude unpipc.h

2 fdefine LOCK PATH pxsemlock

3 sem t *locksem:

4 int initflag:

5 void

6 myjockdnt fd)

8 if (initflag == 0) {

9 locksem - Sem open(PxJpc name(LOCKJATH), OJREAT. FILEJODE. 1):

10 initflag = 1:

11 }

12 Sem wait(locksem):

13 }

14 void

15 my unlock(int fd)

16 {

17 Sem post(locksem):

18 }

Один из семафоров используется для рекомендательной блокировки доступа к файлу и инициализируется единицей при первом вызове функции. Для получения блокировки мы вызываем sem wait, а для ее снятия - sem post.

10.8. Функции semjnit и sem.destroy

До сих пор мы имели дело только с именованными семафорами Posix. Как мы уже говорили, они идентифицируются аргументом пате, обычно представляющим собой имя файла в файловой системе. Стандарт Posix описывает также се-



мафоры, размещаемые в памяти, память под которые выделяет приложение (тип sem t), а инициализируются они системой: finclude <semaphore.h>

int sem init(sem t *sem. int shared, unsigned int value): /* Возвращает -1 в случае ошибки */ int sem destroy(sem t *sem):

/* Возвращает О в случае успешного завершения. -1 - в случае ошибки */ Размещаемый в памяти семафор инициализируется вызовом sem init. Аргумент sem указывает на переменную типа sem t, место под которую должно быть выделено приложением. Если аргумент shared равен О, семафор используется потоками одного процесса, в противном случае доступ к нему могут иметь несколько процессов. Если аргумент shared ненулевой, семафор должен быть размещен в одном из видов разделяемой памяти и должен быть доступен всем процессам, испольйующим его. Как и в вызове sem open, аргумент value задает начальное значение ceVIaфopa.

После завершения работы с размещаемым в памяти семафором его можно уничтожить, вызвав sem destroy.

ПРИМЕЧАНИЕ 1--

Функции sem open не требуется параметр, аналогичный shared; не требуется ей и атрибут, аналогичный PTHREAD PROCESS SHARED (упоминавшийся в связи с взаимными исключениями и условными переменными в главе 7), поскольку именованный семафор всегда используется совместно несколькими процессами.

ПРИМЕЧАНИЕ 2

Обратите внимание, что для размещаемого в памяти семафора нет ничего аналогичного флагу 0 CRE AT: функция sem init всегда инициализирует значение семафора. Следовательно, нужно быть внимательным, чтобы вызывать sem init только один раз для каждого семафора. (Упражнение 10.2 иллюстрирует разницу в этом смысле между именованным и размещаемым в памяти семафорами.) При вызове sem init для уже инициализированного семафора результат непредсказуем.

ПРИМЕЧАНИЕ 3-

Удостоверьтесь, что вы понимаете фундаментальную разницу между sem open и sem init. Первая возвращает указатель на переменную типа sem t, причем выделение места под переменную и ее инициализация выполняются этой же функцией. Напротив, первый аргумент sem init представляет собой указатель на переменную типа sem t, место под которую должен был заранее выделить вызывающий. Функция sem init только инициализирует эту переменную.

ПРИМЕЧАНИЕ 4-

Стандарт Posix.l предупреждает, что для обращения к размещаемым в памяти семафорам можно использовать только указатель, являющийся аргументом при вызове sem init. Использование копий этого указателя может привести к неопределенным результатам.

Функция sem init возвращает -1 в случае ошибки, но она не возвращает О в случае успешного завершения. Это действительно странно, и примечание в Обосновании Posix. 1 говорит, что в будущих версиях функция, возможно, начнет возвращать О в случае успешного завершения.



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

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

Если размещаемый в памяти семафор совместно используется потоками одного процесса (аргумент shared при вызове sem i ni t равен 0), семафор обладает живучестью процесса и удаляется при завершении последнего.

ш Если размещаемый в памяти семафор совместно используется несколькими процессами (аргумент shared при вызове sem init равен 1), он должен располагаться в разделяемой памяти, и в этом случае семафор существует столько, сколько существует эта область памяти. Вспомните, что и разделяемая память Posix, и разделяемая память System V обладают живучестью ядра (табл. 1.1). Это значит, что сервер может создать область разделяемой памяти, инициализировать в ней размещаемый в памяти семафор Posix, а затем завершить работу. Некоторое время спустя один или несколько клиентов могут присоединить эту область к своему адресному пространству и получить доступ к хранящемуся в ней семафору.

Предупреждаем, что нижеследующий код не работает так, как ожидается:

sem t mysen:

Sem init(&mysem. 1, 0): /* 2-щ аргумент 1 -> используется процессами */ if (ForkO 0) { /* дочерни11 процесс */

Sem post(&mysem);

Sem wait(&mysem): /* родительский процесс: ожидание дочернего */

Проблема тут в том, что семафор не располагается в разделяемой памяти (см.раздел 10.12). Память, как правило, не делится между дочерним и родительским процессами при вызове fork. Дочерний процесс запускается с копией памяти родителя, но это не то же самое, что разделяемая память.

Пример

В качестве иллюстрации перепишем наш пример решения задачи производителей и потребителей из листингов 10.8 и 10.9 для использования размещаемых в памяти семафоров Posix. В листинге 10.11 приведен текст новой программы.

Листинг 10.11. Задача производителей и потребителей с использованием размещаемых в памяти семафоров

pxsem/prodcons2.c

1 #inc1ude unpipc.h

2 fdefine NBUFF 10

3 int nitems: /* только для чтения производителем и потребителем */



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.
Копирование материалов разрешено исключительно при условии цититирования.