Наши партнеры

UnixForum





Библиотека сайта 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 ... много серверов хороших и разных Вперед