В листинге 26.7 показана первая часть нашей программы, глобальные переменные и начало функции main
.
Листинг 26.7. Глобальные переменные и начало функции main
//threads/web01.c
1 #include "unpthread.h"
2 #include /* потоки Solaris */
3 #define MAXFILES 20
4 #define SERV "80" /* номер порта или имя службы */
5 struct file {
6 char *f_name; /* имя файла */
7 char *f_host; /* имя узла или IP-адрес */
8 int f_fd; /* дескриптор */
9 int f_flags; /* F_xxx ниже */
10 pthread_t f_tid; /* идентификатор потока */
11 } file[MAXFILES];
12 #define F_CONNECTING 1 /* функция connect () в процессе
выполнения */
13 #define F_READING 2 /* функция connect() завершена;
выполняется считывание */
14 #define F_DONE 4 /* все сделано */
15 #define GET_CMD "GET %s HTTP/1.0\r\n\r\n"
16 int nconn, nfiles, nlefttoconn, nlefttoread;
17 void *do_get_read(void*);
18 void home_page(const char*, const char*);
19 void write_get_cmd(struct file*);
20 int
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 file1 ...");
28 maxnconn = atoi(argv[1]);
29 nfiles = min(argc - 4, MAXFILES);
30 for (i = 0; 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
Мы подключаем заголовочный файл вдобавок к обычному , так как нам требуется использовать потоки 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 0) {
41 /* находим файл для считывания */
42 for (i = 0; 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);
Читать дальше
Конец ознакомительного отрывка
Купить книгу