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

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

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

Пример ситуации, в которой требуется возобновление выполнения нескольких процессов, появится в главе 8, когда мы будем обсуждать задачу с несколькими считывающими и записывающими процессами. Когда записывающий процесс снимает блокировку, он должен разбудить все ждущие считывающие процессы, поскольку одновременное считывание в данном случае разрешено.

Альтернативным (и более безопасным) методом является использование широковещательной передачи во всех тех случаях, когда требуется использование сигналов. Сигнал является оптимизацией для тех случаев, когда известно, что все ожидающие процессы правильно написаны и требуется разбудить только один из них, и какой именно будет разбужен, значения не имеет. Во всех других ситуациях следует использовать широковещательную передачу.

finclude <pthread.h>

int pthread cond broadcast(pthread cond t *cptr):

int pthread cond tiniedwait(pthread cond t *cptr. pthread niutex t *nptr. const struct timespec *abstiwe):

/* Функции возвращают О в случае успешного завершения, положительный код Еххх -в случае ошибки */

Функция pthread cond timedwait позволяет установить ограничение на время блокирования процесса. Аргумент abstime представляет собой структуру timespec;

struct timespec {

time t tv sec; /* секунды */ long tv nsec; /* наносекунды */

Эта структура задает конкретный момент системного времени, в который происходит возврат из функции, даже если сигнал по условной переменной еще не будет получен. В этом случае возвращается ошибка с кодом ETIMEDOUT.

Эта величина представляет собой абсолютное значение времени, а не промежуток. Аргумент abstime задает таким образом количество секунд и наносекунд с 1 января 1970 UTC до того момента времени, в который должен произойти возврат из функции. Это отличает функцию от select, pselect и pol 1 (глава 6 [24]), которые в качестве аргумента принимают некоторое количество долей секунды, спустя которое должен произойти возврат. (Функция select принимает количество микросекунд, pselect - наносекунд, а poll - миллисекунд;) Преимущество использования абсолютного времени заключается в том, что если функция возвратится до ожидаемого момента (например, при перехвате сигнала), ее можно будет вызвать еще раз, не изменяя содержимого структуры timespec.

7.7. Атрибуты взаимных исключений и условных переменных

в наших примерах в этой главе мы хранили взаимные исключения и условные переменные как глобальные данные всего процесса, поскольку они использовались для синхронизации потоков внутри него. Инициализировали мы их с помощью двух констант: PTHREAD MUTEX INITIALIZER и PTHREAD COND INTIALIZER. Инициализируемые таким образом исключения и условные переменные приобретали



значения атрибутов по умолчанию, но мы можем инициализировать их и с другими значениями атрибутов.

Прежде всего инициализировать и удалять взаимное исключение и условную переменную можно с помощью функций

finclude <pthread.h>

int pthread niutex init(pthread niutex t *nptr. const pthread niutexattr t *attr): int pthread niutex destroy(pthread niutex t *nptr):

int pthread cond init(pthread cond t *cptr. const pthread condattr t *attr): int pthread cond destroy(pthread cond t *cptr):

I* Bee четыре функции возвращают О в случае успешного завершения работы, положительное значение Еххх - в случае ошибки */

Рассмотрим, например, взаимное исключение. Аргумент mptr должен указывать на переменную типа pthread niutex t, для которой должна быть уже выделена память, и тогда функция pthread niutex init инициализирует это взаимое исключение. Значение типа pthread niutexattr t, на которое указывает второй аргумент функции pthread niutex init {attr), задает атрибуты этого исключения. Если этот аргумент представляет собой нулевой указатель, используются значения атрибутов по умолчанию.

Атрибуты взаимного исключения имеют тип pthread niutexattr t, а условной переменной - pthread condattr t, и инициализируются и уничтожаются с помощью следующих функций:

finclude <pthread.h>

int pthread niutexattr init(pthread niutexattr t *attr): int pthread niutexattr destroy(pthread niutexattr t *attr): int pthread condattr init(pthread condattr t *attr): int pthread condattr destroy(pthread condattr t *attr):

/* Bee четыре функции возвращают О в случае успешного завершения, положительное значение Еххх - в случае ошибки */

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

finclude <pthread.h>

int pthread mutexattr getpshared(const pthread niutexattr t *attr. int *valptr): int pthread mutexattr setpshared(pthread niutexattr t *attr. int value): int pthread condattr getpshared(const pthread condattr t *attr. int *valptr): int pthread condattr setpshared(pthread condattr t *attr. int value): /* Bee четыре функции возвращают О в случае успешного завершения, положительное значение Еххх - в случае ошибки */

Две функции get возвращают текущее значение атрибута через целое, на которое указывает valptr, а две функции set устанавливают значение атрибута равным значению value. Значение value может быть либо PTHREAD PROCESS PRI VATE, либо PTHREAD PROCESS SHARED. Последнее также называется атрибутом совместного использования процессами.



ПРИМЕЧАНИЕ -

Эта возможность поддерживается только в том случае, если константа POSIX THREAD PROCESS SHARED определена в заголовочном файле <unistd.h>. Она является дополнительной согласно Posix.l и обязательной по Unix 98 (табл. 1.3).

Нижеследующий фрагмент кода показывает, как нужно инициализировать взаимное исключение, чтобы его можно было совместно использовать нескольким процессам:

pthread mutex t *mptr: /* указатель на взаимное исключение, находящееся

в разделяемой памяти */ pthread mutexattr t mattr: /* атрибуты взаимного исключения */

mptr = /* некоторое значение, указывающее на разделяемую память */

Pthread mutexattr init(&mattr):

#i fdef POSIX THREAO PROCESS SHAREO

Pthread mutexattr setpshared(&mattr. PTHREAO PROC£SS SHAREO): #else

# error Эта реализация не поддерживает POSIX THREAO PROCESS SHAREO #endif

Pthread mutex i ni t(mptг, Smattr);

Мы объявляем переменную mattr типа pthread mutexattr t, инициализируем ее значениями атрибутов по умолчанию, а затем устанавливаем атрибут PTHREAD PRDCESS SHARED, позволяющий совместно использовать взаимное исключение нескольким процессам. Затем pthread mutex i nit инициализирует само исключение с соответствующими атрибутами. Количество разделяемой памяти, которое следует выделить под взаимное исключение, равно sizeof(pthread mutex t).

Практически такая же последовательность команд (с заменой mutex на cond) позволяет установить атрибут PTHREAD PRDCESS SHARED для условной переменной, хранящейся в разделяемой несколькими процессами памяти.

Пример совместно используемых несколькими процессами взаимных исключений и условных переменных был приведен в листинге 5.18.

Завершение процесса, заблокировавшего ресурс

Когда взаимное исключение используется совместно несколькими процессами, всегда существует возможность, что процесс будет завершен (возможно, принудительно) во время работы с заблокированным им ресурсом. Не существует способа заставить систему автоматически снимать блокировку во время заверщения процесса. Мы увидим, что это свойственно и блокировкам чтения-записи, и семафорам Posix. Единственный тип блокировок, автоматически снимаемых системой при завершении процесса, - блокировки записей fcntl (глава 9). При использовании семафоров System V можно специально указать ядру, следует ли автоматически снимать блокировки при завершении работы процесса (функция SEM UNDD, о которой будет говориться в разделе 11.3).

Поток также может быть завершен в момент работы с заблокированным ресурсом, если его выполнение отменит (cancel) другой поток или он сам вызовет pthread exi t. Последнему варианту не следует уделять много внимания, посколь-



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