/* Ждем завершения выполнения одного или нескольких потоков */
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
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)
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
и оповещение главного цикла о завершении выполнения потока:
printf("end-of-file on %s\n", fptr->f_name);
Close(fd);
Pthread_mutex_lock(&ndone_mutex);
fptr->f_flags = F_DONE; /* сбрасывает флаг F_READING */
ndone++;
Pthread_cond_signal(&ndone_cond);
Pthread_mutex_unlock(&ndone_mutex);
return(fptr); /* завершение выполнения потока */
}
Большинство изменений касается главного цикла, представленного в листинге 26.8. Новая версия показана в листинге 26.13.
Листинг 26.13. Основной рабочий цикл функции main
//threads/web03.c
Читать дальше
Конец ознакомительного отрывка
Купить книгу