Книга: UNIX: взаимодействие процессов

Автоматическое управление потоками сервера: несколько процедур

Автоматическое управление потоками сервера: несколько процедур

В предыдущем примере процесс-сервер содержал лишь одну процедуру сервера. Вопрос, которым мы займемся теперь, звучит так: могут ли несколько процедур одного процесса использовать один и тот же пул потоков сервера? Чтобы узнать ответ, добавим к нашему серверу еще одну процедуру, а заодно перепишем наши программы заново, чтобы продемонстрировать более приличный стиль передачи аргументов и результатов между процессами.

Первый файл в этом примере называется squareproc.h. В нем определен один тип данных для входных аргументов функции, возводящей в квадрат, и еще один — для возвращаемых ею результатов. В этом заголовочном файле также определяется полное имя двери для данной процедуры. Его текст его приведен в листинге 15.8.

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

//doors/squareproc.h
1 #define PATH_SQUARE_DOOR "/tmp/squareproc_door"
2 typedef struct { /* аргументы squareproc() */
3  long arg1;
4 } squareproc_in_t;
5 typedef struct { /* возврат squareproc() */
6  long res1;
7 } squareproc_out_t;

Наша новая процедура будет принимать длинное целое и возвращать квадратный корень из него (типа double). Мы определяем полное имя двери этой процедуры, структуры аргументов и результатов в заголовочном файле sqrtproc.h в листинге 15.9.

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

//doors/sqrtproc.h
1 #define PATH_SQRT_DOOR "/tmp/sqrtproc_door"
2 typedef struct { /* входные данные sqrtproc() */
3  long arg1;
4 } sqrtproc_in_t;
5 typedef struct { /* возвращаемые sqrtproc() данные */
6  double res1;
7 } sqrtproc_out_t;

Программа-клиент приведена в листинге 15.10. Она последовательно вызывает две процедуры сервера и выводит возвращаемые ими результаты. Эта программа устроена аналогично другим клиентским программам, приведенным в этой главе.

Листинг 15.10. Клиент, вызывающий две процедуры

//doors/client7.c
1  #include "unpipc.h"
2  #include "squareproc.h"
3  #include "sqrtproc.h"
4  int
5  main(int argc, char **argv)
6  {
7   int fdsquare, fdsqrt;
8   door_arg_t arg;
9   squareproc_in_t square_in;
10  squareproc_out_t square_out;
11  sqrtproc_in_t sqrt_in;
12  sqrtproc_out_t sqrt_out;
13  if (argc != 2)
14   err_quit("usage: client7 <integer-value>");
15  fdsquare = Open(PATH_SQUARE_DOOR, O_ROWR);
16  fdsqrt = Open(PATH_SQRT_DOOR, O_RDWR);
17  /* подготовка аргументов и вызов squareproc() */
18  square_in.arg1 = atol(argv[1]);
19  arg.data_ptr = (char*)&square_in;
20  arg.data_size = sizeof(square_in);
21  arg.desc_ptr = NULL;
22  arg.desc_num = 0;
23  arg.rbuf = (char*)&square_out;
24  arg.rsize = sizeof(square_out);
25  Door_call(fdsquare, &arg);
26  /* подготовка аргументов и вызов sqrtproc() */
27  sqrt_in.arg1 = atol(argv[1]);
28  arg.data_ptr = (char*)&sqrt_in;
29  arg.data_size = sizeof(sqrt_in);
30  arg.desc_ptr = NULL;
31  arg.desc_num = 0;
32  arg.rbuf = (char*)&sqrt_out;
33  arg.rsize = sizeof(sqrt_out);
34  Door_call(fdsqrt, &arg);
35  printf("result: %ld %gn", square_out.res1, sqrt_out.res1);
36  exit(0);
37 }

Текст двух серверных процедур приведен в листинге 15.11. Каждая из них выводит текущий идентификатор потока и значение аргумента, делает 5-секунд-ную паузу, вычисляет результат и завершает работу.

Листинг 15.11. Две процедуры сервера

//doors/server7.c
1  #include "unpipc.h"
2  #include <math.h>
3  #include "squareproc.h"
4  #include "sqrtproc.h"
5  void
6  squareproc(void *cookie, char *dataptr, size_t datasize,
7   door_desc_t *descptr, size_t ndesc)
8  {
9   squareproc_in_t in;
10  squareproc_out_t out;
11  memcpy(&in, dataptr, min(sizeof(in), datasize));
12  printf("squareproc: thread id %ld, arg = %ldn",
13   pr_thread_id(NULL), in.arg1);
14  sleep(5);
15  out.res1 = in.arg1 * in.arg1;
16  Door_return((char *) &out, sizeof(out), NULL, 0);
17 }
18 void
19 sqrtproc(void *cookie, char *dataptr, size_t datasize,
20  door_desc_t *descptr, size_t ndesc)
21 {
22  sqrtproc_in_t in;
23  sqrtproc_out_t out;
24  memcpy(&in, dataptr, min(sizeof(in), datasize));
25  printf("sqrtproc: thread id %ld, arg = %ldn",
26   pr_thread_id(NULL), in.arg1);
27  sleep(5);
28  out.res1 = sqrt((double)in.arg1);
29  Door_return((char *) &out, sizeof(out), NULL, 0);
30 }

Функция main сервера, текст которой приведен в листинге 15.12, открывает дескрипторы дверей и связывает каждый из них с одной из процедур сервера.

Листинг 15.12. Функция main сервера

//doors/server7.c
31 int
32 main(int argc, char **argv)
33 {
34  int fd;
35  if (argc != 1)
36   err_quit("usage: server7");
37  fd = Door_create(squareproc, NULL, 0);
38  unlink(PATH_SQUARE_DOOR);
39  Close(Open(PATH_SQUARE_DOOR, O_CREAT | O_RDWR, FILE_MODE));
40  Fattach(fd, PATH_SQUARE_DOOR);
41  fd = Door_create(sqrtproc, NULL, 0);
42  unlink(PATH_SQRT_DOOR);
43  Close(Open(PATH_SQRT_DOOR, O_CREAT | O_RDWR, FILE_MODE));
44  Fattach(fd, PATH_SQRT_DOOR);
45  for (;;)
46   pause();
47 }

Запустим программу-клиент и подождем 10 секунд до вывода результатов (как мы и ожидали):

solaris % client7 77
result: 5929 8.77496

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

solaris % server7
squareproc: thread id 4, arg = 77
sqrtproc: thread id 4, arg = 77

Это подтверждает наши предположения о том, что любой поток из пула сервера может использоваться при обработке запросов клиентов для любой процедуры.

Оглавление книги


Генерация: 1.195. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз