Библиотека сайта rus-linux.net
Назад | Сервер TCP/IP ... много серверов хороших и разных | Вперед |
Сервер с предварительным созданием потоков
В точности так же, как мы это делали с предварительным созданием клона процесса (ech11.cc), мы можем создать сервер (файл ech22.cc), который будет предварительно создавать новый поток, который будет заблокирован на accept() в ожидании запроса на обслуживание. Мы, фактически, поменяли местами вызовы pthread_create() и accept() в предыдущей схеме. Текст такого сервера:
#include <pthread.h> #include "common.h" static int ntr = 3; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t condvar = PTHREAD_COND_INITIALIZER; void* echo( void* ps ) { int sc = *(int*)ps, rs; sched_yield(); if( ( rs = accept( sc, NULL, NULL ) ) < 0 ) errx( "accept error" ); retrans( rs ); close( rs ); pthread_mutex_lock( &mutex ); ntr++; pthread_cond_signal( &condvar ); pthread_mutex_unlock( &mutex ); if( debug ) cout < pthread_self() < '.' < flush; delay( 250 ); // пауза 250 usec. return NULL; } // ретранслятор c предварительным pthread_create() int main( int argc, char *argv[] ) { int ls = getsocket( PRETHREAD_PORT ), rs; setv( argc, argv ); while( true ) { pthread_t tid; if( pthread_create( &tid, NULL, &echo, &ls ) != EOK ) errx( "thread create error" ); sched_yield(); pthread_mutex_lock( &mutex ); ntr--; while( ntr <= 0 ) pthread_cond_wait( &condvar, &mutex ); pthread_mutex_unlock( &mutex ); }; exit( EXIT_SUCCESS ); };
Здесь accept() перенесен в обрабатывающий поток (все созданные потоки блокированы в accept() на единственном прослушивающем сокете). Какой конкретно из потоков будет разблокирован для обработки при получении запроса — непредсказуемо! Для синхронизации я использую условную переменную, но могут применяться любые из синхронизирующих примитивов. Испытываем полученную программу:
$ sudo nice -n19 ./ech22 -v waiting on port 51007 ... verbose mode 3074657136.3066264432.3057871728.3049479024.3041086320.3032693616.3024300912. 3015908208.3007515504.2999122800.2990730096.2982337392.2973944688.2965551984. 2957159280.2948766576.2940373872.2931981168.2923588464.2915195760. $ ./cli -a 192.168.1.5 -p 51007 -n 20 host: 192.168.1.5, TCP port = 51007, number of echoes = 20 time of reply - Cycles [usec.] : 2558382[833] 432722[140] 485587[158] 461599[150] 483759[157] 457838[149] 466141[151] 458367[149] 462622[150] 541121[176] 461081[150] 570228[185] 457619[149] 450570[146] 458977[149] 440369[143] 461898[150] 467740[152] 474179[154] 462726[150]
Время реакции очень близко к последовательному серверу (к минимально достижимой потенциально асимптоте, в смысле времени получения ответа!). Потоки обработчики на сервере идентифицируют себя своим pthread_t: 3074657136.3066264432... Хорошо видно как последовательно порождаются новые потоки для обработки каждого запроса клиента. Так же сильно (но не настолько, как и в предыдущем случае) выражены эффекты кэширования.
Назад | Сервер TCP/IP ... много серверов хороших и разных | Вперед |