21 main(int argc, char **argv)
22 {
23 int i, n, maxnconn;
24 pthread_t tid;
25 struct file *fptr;
26 if (argc 5)
27 err_quit("usage: web #conns IPaddr homepage file1 ...");
28 maxnconn = atoi(argv[1]);
29 nfiles = min(argc - 4, MAXFILES);
30 for (i = 0; i nfiles; i++) {
31 file[i].f_name = argv[i + 4];
32 file[i].f_host = argv[2];
33 file[i].f_flags = 0;
34 }
35 printf("nfiles = %d\n", nfiles);
36 home_page(argv[2], argv[3]);
37 nlefttoread = nlefttoconn = nfiles;
38 nconn = 0;
1-16
thread.h
вдобавок к обычному
pthread.h
, так как нам требуется использовать потоки Solaris в дополнение к потокам Pthreads, как мы вскоре покажем.10
file
один элемент — идентификатор потока f
_tid
. Остальная часть этого кода аналогична коду в листинге 16.9. В этой версии нам не нужно использовать функцию
select
, а следовательно, не нужны наборы дескрипторов и переменная
maxfd
.36
home_page
не изменилась относительно листинга 16.10. В листинге 26.8 показан основной рабочий цикл потока main.Листинг 26.8
. Основной рабочий цикл потока main//threads/web01.c
39 while (nlefttoread 0) {
40 while (nconn maxnconn nlefttoconn 0) {
41 /* находим файл для считывания */
42 for (i = 0; i nfiles; i++)
43 if (file[i].f_flags == 0)
44 break;
45 if (i == nfiles)
46 err_quit("nlefttoconn = %d but nothing found", nlefttoconn);
47 file[i].f_flags = F_CONNECTING;
48 Pthread_create(tid, NULL, do_get_read, file[i]);
49 file[i].f_tid = tid;
50 nconn++;
51 nlefttoconn--;
52 }
53 if ((n = thr_join(0, tid, (void**)fptr)) != 0)
54 errno = n, err_sys("thr_join error");
55 nconn--;
56 nlefttoread--;
57 printf("thread id %d for %s done\n", tid, fptr-f_name);
58 }
59 exit(0);
60 }
40-52
nconn
меньше, чем
maxconn
), мы так и делаем. Функция, которую выполняет каждый новый поток, — это
do_get_read
, а ее аргументом является указатель на структуру
file
.53-54
thr_join
Solaris с нулевым первым аргументом, чтобы дождаться завершения выполнения какого-либо из наших потоков. К сожалению, в Pthreads не предусмотрен способ, с помощью которого мы могли бы ждать завершения выполнения любого потока, и функция
pthread_join
требует, чтобы мы точно указали, завершения какого потока мы ждем. В разделе 26.9 мы увидим, что решение этой проблемы в случае применения технологии Pthreads оказывается сложнее и требует использования условной переменной для сообщения главному потоку о завершении выполнения дополнительного потока.Показанное здесь решение, в котором используется функция потоков thr_join Solaris, не является, вообще говоря, совместимым со всеми системами. Тем не менее мы приводим здесь эту версию веб-клиента, использующую потоки, чтобы не осложнять обсуждение рассмотрением условных переменных и взаимных исключений (mutex). К счастью, в Solaris допустимо смешивать потоки Pthreads и потоки Solaris.
В листинге 26.9 показана функция
do_get_read
, которая выполняется каждым потоком. Эта функция устанавливает соединение TCP, посылает серверу команду HTTP
GET
и считывает ответ сервера.Листинг 26.9
. Функция do_get_read//threads/web01.c