UNIX: разработка сетевых приложений
Шрифт:
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; /* сервер закрывает соединение */
77 printf ("read %d bytes from %s\n", n, fptr->f_name);
78 }
79 printf("end-of-file on %s\n\", fptr->f_name);
80 Close(fd);
81 fptr->f_flags = F_DONE; /* сбрасываем F_READING */
82 return (fptr); /* завершение потока */
83 }
Создание сокета TCP, установление соединения
68-71
Создается сокет TCP, и с помощью функции tcp_connect
устанавливается соединение. В данном случае используется обычный блокируемый сокет, поэтому поток будет блокирован при вызове функции connect
, пока не будет установлено соединение. Отправка запроса серверу
72
Функция write_get_cmd
формирует команду HTTP GET
и отсылает ее серверу. Мы не показываем эту функцию заново, так как единственным отличием от листинга 16.12 является то, что в версии, использующей потоки, не вызывается макрос FD_SET
и не используется maxfd
. Чтение ответа сервера
73-82
Затем считывается ответ сервера. Когда соединение закрывается сервером, устанавливается флаг F_DONE
и функция возвращает управление, завершая выполнение потока. Мы также не показываем функцию
home_page
, так как она полностью повторяет версию, приведенную в листинге 16.10. Мы вернемся к этому примеру, заменив функцию Solaris
thr_join
на более переносимую функцию семейства Pthreads, но сначала нам необходимо обсудить взаимные исключения и условные переменные. 26.7. Взаимные исключения
Обратите внимание на то, что в листинге 26.8 при завершении выполнения очередного потока в главном цикле уменьшаются на единицу и
nconn
, и nlefttoread
. Мы могли бы поместить оба эти оператора уменьшения в одну функцию do_get_read
, что позволило бы каждому потоку уменьшать эти счетчики непосредственно перед тем, как выполнение потока завершается. Но это привело бы к возникновению трудноуловимой серьезной ошибки параллельного программирования.
Поделиться:
Популярные книги
Para bellum
4. Фрунзе
Фантастика:
попаданцы
альтернативная история
6.60
рейтинг книги
Последний рейд
5. Медорфенов
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 9
9. Лекарь
Фантастика:
боевая фантастика
юмористическое фэнтези
6.00
рейтинг книги
Муж на сдачу
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Последняя Арена 7
7. Последняя Арена
Фантастика:
рпг
постапокалипсис
5.00
рейтинг книги
Мастер 7
7. Мастер
Фантастика:
фэнтези
боевая фантастика
попаданцы
технофэнтези
аниме
5.00
рейтинг книги
Иван Московский. Первые шаги
1. Иван Московский
Фантастика:
героическая фантастика
альтернативная история
5.67
рейтинг книги
Случайная жена для лорда Дракона
Фантастика:
юмористическая фантастика
попаданцы
5.00
рейтинг книги
Идеальный мир для Социопата 2
2. Социопат
Фантастика:
боевая фантастика
рпг
6.11
рейтинг книги
Войны Наследников
9. Десять Принцев Российской Империи
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Попаданка для Дракона, или Жена любой ценой
Любовные романы:
любовно-фантастические романы
7.17
рейтинг книги
Серые сутки
4. Медорфенов
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Баоларг
12. Другая сторона
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Кодекс Крови. Книга III
3. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00