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

на главную

Жанры

UNIX: разработка сетевых приложений
Шрифт:

Почему взаимное исключение всегда связано с условной переменной? «Условие» обычно представляет собой значение некоторой переменной, используемой совместно несколькими потоками. Взаимное исключение требуется для того, чтобы различные потоки могли задавать и проверять значение условной переменной. Например, если в примере кода, приведенном ранее, отсутствовало бы взаимное исключение, то проверка в главном цикле выглядела бы следующим образом:

/* Ждем завершения выполнения одного или нескольких потоков */

while (ndone == 0)

Pthread_cond_wait(&ndone_cond, &ndone_mutex);

Но

при этом существует вероятность, что последний поток увеличивает значение переменной
ndone
после проверки главным потоком условия
ndone == 0
, но перед вызовом функции
pthread_cond_wait
. Если это происходит, то последний «сигнал» теряется, и основной цикл оказывается заблокированным навсегда, так как он будет ждать события, которое никогда не произойдет.

По этой же причине при вызове функции

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

/* Ждем завершения выполнения одного или нескольких потоков */

Pthread_mutex_lock(&ndone_mutex);

while (ndone == 0) {

Pthread_mutex_unlock(&ndone_mutex);

Pthread_cond_wait(&ndone_cond, &ndone_mutex);

Pthread_mutex_lock(&ndone_mutex);

}

Существует вероятность того, что по завершении выполнения поток увеличит на единицу значение переменной

ndone
и это произойдет между вызовом функций
pthread_mutex_unlock
и
pthread_cond_wait
.

Обычно функция

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

#include <pthread.h>

int pthread_cond_broadcast(pthread_cond_t * cptr);

int pthread_cond_timedwait(pthread_cond_t * cptr, pthread_mutex_t * mptr,

const struct timespec * abstime);

Обе функции возвращают: 0 в случае успешного выполнения, положительное значение Exxx в случае ошибки

Функция

pthread_cond_timedwait
позволяет потоку задать предельное время блокирования. Аргумент
abstime
представляет собой структуру
timespec
(определенную в разделе 6.9 при рассмотрении функции
pselect
), которая задает системное время для момента, когда функция должна возвратить управление, даже если к этому моменту условная переменная не подала
сигнал. Если возникает такая ситуация, возвращается ошибка
ETIME
.

В данном случае значение времени является абсолютным значением времени, в отличие от относительного значения разницы во времени( time delta) между некоторыми событиями. Иными словами,

abstime
— это системное время, то есть количество секунд и наносекунд, прошедших с 1 января 1970 года (UTC) до того момента, когда эта функция должна вернуть управление. Здесь имеется различие как с функцией
pselect
, так и с функцией
select
, задающими количество секунд (и наносекунд в случае
pselect
) до некоторого момента в будущем, когда функция должна вернуть управление. Обычно для этого вызывается функция
gettimeofday
, которая выдает текущее время (в виде структуры
timeval
), а затем оно копируется в структуру
timespec
и к нему добавляется требуемое значение:

struct timeval tv;

struct timespec ts;

if (gettimeofday(&tv, NULL) < 0)

err_sys("gettimeofday error");

ts.tv_sec = tv.tv_sec + 5; /* 5 с в будущем */

ts.tv_nsec = tv.tv_usec * 1000; /* микросекунды переводим в наносекунды */

pthread_cond_timedwait( , &ts);

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

timespec
. Недостаток этого способа заключается в необходимости вызывать дополнительно функцию
gettimeofday
перед тем, как в первый раз вызывать функцию
pthread_cond_timedwait
.

ПРИМЕЧАНИЕ

В POSIX определена новая функция clock_gettime, возвращающая текущее время в виде структуры timespec.

26.9. Веб-клиент и одновременный доступ

Изменим код нашего веб-клиента из раздела 26.6: уберем вызов функции Solaris

thr_join
и заменим его вызовом функции
pthread_join
. Как сказано в разделе 26.6, теперь нам нужно точно указать, завершения какого потока мы ждем. Для этого мы используем условную переменную, описанную в разделе 26.8.

Единственным изменением в отношении глобальных переменных (см. листинг 26.7) является добавление нового флага и условной переменной:

#define F_JOINED 8 /* количество потоков */

int ndone; /* количество завершившихся потоков */

pthread_mutex_t ndone_mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t ndone_cond = PTHREAD_COND_IINITIALIZER;

Единственным изменением функции

do_get_read
(см. листинг 26.9) будет увеличение на единицу значения переменной
ndone
и оповещение главного цикла о завершении выполнения потока:

Поделиться:
Популярные книги

Имя нам Легион. Том 3

Дорничев Дмитрий
3. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 3

Метатель. Книга 2

Тарасов Ник
2. Метатель
Фантастика:
боевая фантастика
попаданцы
рпг
фэнтези
фантастика: прочее
постапокалипсис
5.00
рейтинг книги
Метатель. Книга 2

Безумный Макс. Ротмистр Империи

Ланцов Михаил Алексеевич
2. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
4.67
рейтинг книги
Безумный Макс. Ротмистр Империи

Болотник

Панченко Андрей Алексеевич
1. Болотник
Фантастика:
попаданцы
альтернативная история
6.50
рейтинг книги
Болотник

Темный Лекарь 6

Токсик Саша
6. Темный Лекарь
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Темный Лекарь 6

Архил...? Книга 2

Кожевников Павел
2. Архил...?
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Архил...? Книга 2

Целитель

Первухин Андрей Евгеньевич
1. Целитель
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Целитель

Ты всё ещё моя

Тодорова Елена
4. Под запретом
Любовные романы:
современные любовные романы
7.00
рейтинг книги
Ты всё ещё моя

Зауряд-врач

Дроздов Анатолий Федорович
1. Зауряд-врач
Фантастика:
альтернативная история
8.64
рейтинг книги
Зауряд-врач

Авиатор: назад в СССР

Дорин Михаил
1. Авиатор
Фантастика:
попаданцы
альтернативная история
5.25
рейтинг книги
Авиатор: назад в СССР

Мастер 3

Чащин Валерий
3. Мастер
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер 3

Фараон

Распопов Дмитрий Викторович
1. Фараон
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Фараон

На изломе чувств

Юнина Наталья
Любовные романы:
современные любовные романы
6.83
рейтинг книги
На изломе чувств

Энфис 2

Кронос Александр
2. Эрра
Фантастика:
героическая фантастика
рпг
аниме
5.00
рейтинг книги
Энфис 2