Чтение онлайн

на главную

Жанры

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

17 for (i = 0; i < nthreads; i++)

18 thread_make(i); /* завершается только основной поток */

19 Signal(SIGINT, sig_int);

20 for (;;)

21 pause; /* потоки все выполнили */

22 }

Функции

thread_make
и
thread_main
показаны в листинге 30.23.

Листинг 30.23. Функции thread_make и thread_main

//server/pthread07.c

1 #include "unpthread.h"

2 #include "pthread07.h"

3 void

4 thread_make(int i)

5 {

6 void *thread_main(void*);

7 Pthread_create(&tptr[i].thread_tid, NULL, &thread_main, (void*)i);

8 return; /*
завершается основной поток */

9 }

10 void*

11 thread_main(void *arg)

12 {

13 int connfd;

14 void web_child(int);

15 socklen_t clilen;

16 struct sockaddr *cliaddr;

17 cliaddr = Malloc(addrlen);

18 printf("thread %d starting\n", (int)arg);

19 for (;;) {

20 clilen = addrlen;

21 Pthread_mutex_lock(&mlock);

22 connfd = Accept(listenfd, cliaddr, &clilen);

23 Pthread_mutex_unlock(&mlock);

24 tptr[(int)arg].thread_count++;

25 web_child(connfd); /* обработка запроса */

26 Close(connfd);

27 }

28 }

Создание потоков

7
Создаются потоки, каждый из которых выполняет функцию
pthread_main
. Единственным аргументом этой функции является порядковый номер потока.

21-23
Функция
thread_main
вызывает функции
pthread_mutex_lock
и
pthread_mutex_unlock
соответственно до и после вызова функции
accept
.

Сравнивая строки 6 и 7 в табл. 30.1, можно заметить, что эта последняя версия нашего сервера быстрее, чем версия с созданием нового потока для каждого клиентского запроса. Этого можно было ожидать, так как в данной версии мы сразу создаем пул потоков и не тратим время на создание новых потоков по мере поступления клиентских запросов. На самом деле эта версия сервера — самая быстродействующая для всех операционных систем, которые мы испытывали.

В табл. 30.2 показано распределение значений счетчика

thread_count
структуры
Thread
, которые мы выводим с помощью обработчика сигнала
SIGINT
по завершении работы сервера. Равномерность этого распределения объясняется тем, что при выборе потока, который будет блокировать взаимное исключение, алгоритм планирования загрузки потоков последовательно перебирает все потоки в цикле.

ПРИМЕЧАНИЕ

В Беркли-ядрах нам не нужна блокировка при вызове функции accept, так что мы можем использовать версию, представленную в листинге 30.23, без взаимных исключений. Но в результате этого время, затрачиваемое центральным процессором, увеличится. Если рассмотреть два компонента, из которых складывается время центрального процессора — пользовательское и системное время — то окажется, что первый компонент уменьшается при отсутствии блокировки (поскольку блокирование осуществляется в библиотеке потоков, входящей в пользовательское пространство), но системное время возрастает (за счет эффекта «общей побудки», возникающего, когда все потоки, блокированные в вызове функции accept, выходят из состояния ожидания при появлении нового клиентского соединения). Для того чтобы каждое соединение передавалось только одному потоку, необходима некая разновидность взаимного исключения, и оказывается, что быстрее это делают сами потоки, а не ядро.

30.12. Сервер с предварительным порождением потоков: основной поток вызывает функцию accept

Последняя рассматриваемая нами версия сервера устроена следующим образом: главный поток создает пул потоков при запуске сервера, после чего он же вызывает функцию

accept
и передает каждое клиентское соединение какому-либо из свободных на данный момент потоков. Это аналогично передаче дескриптора в версии, рассмотренной нами в разделе 30.9.

При таком устройстве сервера необходимо решить, каким именно образом должна осуществляться передача присоединенного дескриптора одному из потоков в пуле. Существует несколько способов решения этой задачи. Можно, как и прежде, использовать передачу дескриптора, но при этом не требуется передавать дескриптор от одного потокам к другому, так как все они, в том числе и главный поток, принадлежат одному и тому же процессу. Все, что требуется знать потоку, получающему дескриптор, — это номер дескриптора. В листинге 30.24 показан заголовочный файл

pthread08.h
, определяющий структуру
Thread
, аналогичный файлу, показанному в листинге 30.21.

Листинг 30.24. Заголовочный файл pthread08.h

//server/pthread08.h

1 typedef struct {

2 pthread_t thread_tid; /* идентификатор потока */

3 long thread_count; /* количество обработанных запросов */

4 } Thread;

5 Thread *tptr; /* массив структур Thread */

6 #define MAXNCLI 32

7 int clifd[MAXNCLI], iget, iput;

8 pthread_mutex_t clifd_mutex;

9 pthread_cond_t clifd_cond;

Определение массива для записи дескрипторов присоединенных сокетов

6-9 Мы определяем массив

clifd
, в который главный поток записывает дескрипторы присоединенных сокетов. Свободные потоки из пула получают по одному дескриптору из этого массива и обрабатывают соответствующий запрос,
iput
— это индекс в данном массиве для очередного элемента, записываемого в него главным потоком, a
iget
— это индекс очередного элемента массива, передаваемого свободному потоку для обработки. Разумеется, эта структура данных, совместно используемая всеми потоками, должна быть защищена, и поэтому мы используем условную переменную и взаимное исключение.

В листинге 30.25 показана функция

main
.

Листинг 30.25. Функция main для сервера с предварительным порождением потоков

//server/serv08.c

1 #include "unpthread.h"

2 #include "pthread08.h"

3 static int nthreads;

4 pthread_mutex_t clifd_mutex = PTHREAD_MUTEX_INITIALIZER;

5 pthread_cond_t clifd_cond = PTHREAD_COND_INITIALIZER;

Поделиться:
Популярные книги

Мужчина моей судьбы

Ардова Алиса
2. Мужчина не моей мечты
Любовные романы:
любовно-фантастические романы
8.03
рейтинг книги
Мужчина моей судьбы

Разбуди меня

Рам Янка
7. Серьёзные мальчики в форме
Любовные романы:
современные любовные романы
остросюжетные любовные романы
5.00
рейтинг книги
Разбуди меня

Неверный

Тоцка Тала
Любовные романы:
современные любовные романы
5.50
рейтинг книги
Неверный

На границе империй. Том 9. Часть 2

INDIGO
15. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 9. Часть 2

Небо для Беса

Рам Янка
3. Самбисты
Любовные романы:
современные любовные романы
5.25
рейтинг книги
Небо для Беса

Жребий некроманта 3

Решетов Евгений Валерьевич
3. Жребий некроманта
Фантастика:
боевая фантастика
5.56
рейтинг книги
Жребий некроманта 3

Черный Маг Императора 7 (CИ)

Герда Александр
7. Черный маг императора
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Черный Маг Императора 7 (CИ)

Его маленькая большая женщина

Резник Юлия
Любовные романы:
современные любовные романы
эро литература
8.78
рейтинг книги
Его маленькая большая женщина

Зауряд-врач

Дроздов Анатолий Федорович
1. Зауряд-врач
Фантастика:
альтернативная история
8.64
рейтинг книги
Зауряд-врач

Законы Рода. Том 4

Flow Ascold
4. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 4

Проводник

Кораблев Родион
2. Другая сторона
Фантастика:
боевая фантастика
рпг
7.41
рейтинг книги
Проводник

Возмездие

Злобин Михаил
4. О чем молчат могилы
Фантастика:
фэнтези
7.47
рейтинг книги
Возмездие

Восход. Солнцев. Книга XI

Скабер Артемий
11. Голос Бога
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Восход. Солнцев. Книга XI

Курсант: Назад в СССР 10

Дамиров Рафаэль
10. Курсант
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Курсант: Назад в СССР 10