Читать «UNIX: взаимодействие процессов» онлайн - страница 270
Уильям Ричард Стивенс
17 }
Объявление переменной для помещения результата
8 Мы объявляем переменную типа square_out, а не указатель на нее.
Новый аргумент в вызове процедуры
12-14 Вторым аргументом вызова squareproc_2 становится указатель на переменную out, а последним аргументом является дескриптор клиента. Вместо возвращения указателя на результат (как в листинге 16.2) эта функция будет возвращать либо RPC_SUCCESS, либо некоторое другое значение в случае возникновения ошибок. Перечисление enumclnt_stat в заголовочном файле <rpc/clnt_stat.h> содержит все возможные коды ошибок.
В листинге 16.6 приведен текст новой процедуры сервера. Как и программа из листинга 16.4, эта версия выводит идентификатор потока, ждет 5 секунд, а затем завершает работу.
Листинг 16.6. Процедура многопоточного сервера
//sunrpc/square3/server.c
1 #include "unpipc.h"
2 #include "square.h"
3 bool_t
4 squareproc_2_svc(square_in *inp, square_out *outp, struct svc_req *rqstp)
5 {
6 printf("thread %Id started, arg = %ld\n",
7 pr_thread_id(NULL), inp->arg1);
8 sleep(5);
9 outp->res1 = inp->arg1 * inp->arg1;
10 printf("thread %ld done\n", pr_thread_id(NULL));
11 return(TRUE);
12 }
13 int
14 square_prog_2_freeresult(SVCXPRT *transp, xdrproc_t xdr_result,
15 caddr_t result)
16 {
17 xdr_free(xdr_result, result);
18 return(1);
19 }
Новые аргументы и возвращаемое значение
3-12 Требуемые для реализации многопоточности изменения включают изменение аргументов функций и возвращаемого значения. Вместо возвращения указателя на структуру результатов (как в листинге 16.3) указатель на эту структуру принимается в качестве второго аргумента функции. Указатель на структуру svc_req смещается на третью позицию. Теперь при успешном завершении функции возвращается значение TRUE, а при возникновении ошибок — FALSE.
Новая функция, освобождающая память XDR
13-19 Еще одно изменение заключается в добавлении функции, освобождающей все автоматически выделенные переменные. Эта функция вызывается из заглушки сервера после завершения работы процедуры сервера и отправки результата клиенту. В нашем примере просто делается вызов подпрограммы xdr_free (о ней будет говориться более подробно в связи с листингом 16.19 и упражнением 16.10).
Если процедура сервера выделяла память под сохраняемый результат (например, в виде связного списка), этот вызов освободит занятую память.
Создадим программу-клиент и программу-сервер и запустим три экземпляра клиента одновременно:
solaris % client localhost 55 & client localhost 66 & client localhost 77 &
[3] 25427
[4] 25428
[5] 25429
solaris % result: 4356
result: 3025
result: 5929
На этот раз мы видим, что результаты выводятся одновременно, один за другим. Взглянув на выводимый сервером текст, отметим, что используются три серверных потока и все они выполняются одновременно:
solaris % server
thread 1 started, arg = 55
thread 4 started, arg = 77
thread 6 started, arg = 66
thread 6 done
thread 1 done
thread 4 done
ПРИМЕЧАНИЕ
Одним из печальных следствий изменений, требуемых для реализации многопоточности, является уменьшение количества систем, поддерживающих новый код. Например, в Digital Unix 4.0B и BSD/OS 3.1 используется старая система RPC, не поддерживающая многопоточность. Это означает, что если мы хотим компилировать и использовать нашу программу в системах обоих типов, нам нужно использовать условия #ifdef для обработки различий в вызовах клиента и сервера. Конечно, клиент в BSD/OS, не являющийся многопоточным, может вызвать процедуру многопоточного сервера в Solaris, но если мы хотим, чтобы клиент или сервер компилировался в обоих типах систем, исходный код нужно изменить, предусмотрев различия.