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

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

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 %sn", 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
43  while (nlefttoread > 0) {
44   while (nconn < maxnconn && nlefttoconn > 0) {
45    /* находим файл для считывания */
46    for (i = 0; i < nfiles; i++)
47     if (file[i].f_flags == 0)
48      break;
49    if (i == nfiles)
50     err_quit("nlefttoconn = %d but nothing found", nlefttoconn);
51    file[i].f_flags = F_CONNECTING;
52    Pthread_create(&tid, NULL, &do_get_read, &file[i]);
53    file[i].f_tid = tid;
54    nconn++;
55    nlefttoconn--;
56   }
57   /* Ждем завершения выполнения одного из потоков */
58   Pthread_mutex_lock(&ndone_mutex);
59   while (ndone == 0)
60    Pthread_cond_wait(&ndone_cond, &ndone_mutex);
61   for (i = 0; i < nfiles; i++) {
62    if (file[i].f_flags & F_DONE) {
63     Pthread_join(file[i].f_tid, (void**)&fptr);
64     if (&file[i] != fptr)
65      err_quit("file[i] != fptr");
66     fptr->f_flags = F_JOINED; /* clears F_DONE */
67     ndone--;
68     nconn--;
69     nlefttoread--;
70     printf("thread %d for %s donen", fptr->f_tid, fptr->f_name);
71    }
72   }
73   Pthread_mutex_unlock(&ndone_mutex);
74  }
75  exit(0);
76 }

По возможности создаем новый поток

44-56 Эта часть кода не изменилась.

Ждем завершения выполнения потока

57-60 Мы ждем завершения выполнения потоков, отслеживая, когда значение ndone станет равно нулю. Как сказано в разделе 26.8, эта проверка должна быть проведена перед тем, как взаимное исключение будет блокировано, а переход потока в состояние ожидания осуществляется функцией pthread_cond_wait.

Обработка завершенного потока

61-73 Когда выполнение потока завершилось, мы перебираем все структуры file, отыскивая соответствующий поток, вызываем pthread_join, а затем устанавливаем новый флаг F_JOINED.

В табл. 16.1 показано, сколько времени требует выполнение этой версии веб-клиента, а также версии, использующей неблокируемую функцию connect.

Оглавление книги


Генерация: 1.473. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз