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

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

7 key t key:

8 lf ( (key = ftok(pathname. 0)) == (key t) -1)

9 return(-l):

10 if (unlink(pathname) == -1)

11 return(-l):

12 if ( (semid = semget(key. 1. SVSEM MODE)) == -1)

13 return(-l):

14 if (semcti(semid. 0. IPC RMID) =- -1)

15 return(-l):

16 return(O):

17 }

Листинг 10.41. Функция sem post

my pxsem svsem/sem post.c

1 finclude unpipc.h

2 finclude semaphore.h

3 int

4 mysem post(mysem t *sem)

6 struct sembuf op:

7 if (sem->sem magic != SEM MAGIC) {

8 errno = EINVAL:

9 return(-l):

10 }

11 op.sem num = 0:

12 op.sem op = 1:

13 op.sem flg = 0:

14 if (semop(sem->sem semid. &op. 1) < 0)

15 return(-l):

16 return(O):

17 }

Листинг 10.42. Функция sem wait

my pxsem svsem/sem wait.с

1 finclude unpipc.h

2 finclude semaphore.h

3 int

4 mysem wait(mysem t *sem)

6 struct sembuf op;

7 if (sem->sem magic != SEM MAGIC) {

8 errno = EINVAL:

9 return(-l):

10 }

11 op.sem num = 0:

12 op.sem op = -1:

13 op.sem flg = 0:

14 if (semop(sem->sem semid. &op. 1) < 0)

15 return(-l): л

продолжение



Листинг 10.42 (продолжение)

16 return(O):

17 }

Функция sem trywait

в листинге 10.43 приведен текст нашей функции sem trywait, которая представляет собой неблокируемую версию sem wa1t. 13 Единственное отличие от функции sem wait из листинга 10.42 заключается в том, что флагу sem flg присваивается значение IPC NOWAIT. Если операция не может быть завершена без блокирования вызвавшего потока, функция semop возвращает ошибку EAGAIN, а это именно тот код, который должен быть возвращен sem trywait, если операция не может быть завершена без блокирования потока.

Листинг 10.43. Функция semjrywait

my pxsem svsem/sem trywait.с

1 finclude unpipc.h

2 finclude semaphore.h

3 int

4 mysem trywait(mysemj *sem)

5 {

6 struct sembuf op:

7 if (sem->sem magic !- SEM MAGIC) {

8 errno = EINVAL:

9 return(-l):

10 }

11 op.sem num - 0:

12 op.sem op = -1:

13 op. sem Jig = IPCJOWAIT:

14 if (semop(sem->sem semid. &op. 1) < 0)

15 return(-l):

16 return(O):

17 }

Функция sem getvalue

Последняя функция приведена в листинге 10.44. Это функция sem getvalue, возвращающая текущее значение семафора. 11-14 Текущее значение семафора получается отправкой команды GETVAL функции semctl.

Листинг 10.44. Функция sem getvalue

my pxsem svsem/sem getvalue. с

1 finclude unpipc.h

2 finclude semaphore.h

3 int

4 iT\ysem getvalue(iT\ysemJ *sem. int *pvalue)

5 {

6 int val:

7 if (sem->sem magic !- SEMJAGIC) {.

8 errno = EINVAL:



9 return(-l):

10 }

11 if ( (vai = semctl(sem->sem semid. 0. GETVAD) < 0)

12 return(-l):

13 *pvalue = vai:

14 return(O):

15 }

10.17. Резюме

Семафоры Posix представляют собой семафоры-счетчики, для которых определены три основные операции:

1. Создание семафора.

2. Ожидание изменения значения семафора на ненулевое и последующее умень-щение значения.

3. Увеличение значения семафора на 1 и возобновление выполнения всех процессов, ожидающих его изменения.

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

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

В этой главе было приведено три примера возможной реализации семафоров Posix. Первый пример был самым простым, в нем использовались каналы FIFO, а большая часть забот по синхронизации ложилась на ядро (функции read и wri te). Следующая реализация использовала отображение файлов в память (аналогично реализации очередей сообщений Posix из раздела 5.8), а также взаимное ис-1слючение и условную переменную (для синхронизации). Последняя реализация была основана на семафорах System V и представляла собой, по сути, удобный интерфейс для работы с ними.

Упражнения

1. Измените функции produce и consume из раздела 10.6 следующим образом. Поменяйте порядок двух вызовов Sem wa i t в потребителе, чтобы возникла ситуация зависания (как описано в разделе 10.6). Затем добавьте вызов printf перед



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