UNIX: разработка сетевых приложений
Шрифт:
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
61 void*
62 do_get_read(void *vptr)
63 {
64 int fd, n;
65 char line[MAXLINE];
66 struct file *fptr;
67 fptr = (struct file*)vptr;
68 fd = Tcp_connect(fptr->f_host, SERV);
69 fptr->f_fd = fd;
70 printf("do_get_read for %s, fd %d, thread %d\n",
71 fptr->f_name, fd, fptr->f_tid);
72 write_get_cmd(fptr);
73 /* Чтение ответа сервера */
74 for (;;) {
75 if ((n = Read(fd, line, MAXLINE)) == 0)
76 break; /* сервер закрывает соединение */
Поделиться с друзьями: