マルチスレッド・ユーザー・モードでは、サービス手続きは、戻しの前に svc_done() を呼び出さなければなりません。svc_done() は、クライアント要求が指定のサービス・トランスポート・ハンドルに向けたサービスに割り当てたリソースを解放しなければなりません。この機能は、クライアント要求がサービスされた後、あるいは応答の送信を妨げたエラーまたは異常な状態の後に呼び出されます。svc_done() が呼び出された後に、サービス・トランスポート・ハンドルは、サービス手続きによって参照されるべきではありません。例 4-41 は、マルチスレッド・ユーザー・モードでのサーバーを示します。
svc_done() は、マルチスレッド・ユーザー・モード内でだけ呼び出すことができます。詳細は、rpc_svc_calls(3NSL) のマニュアルページを参照してください。
#define SVC2_PROG 0x30000002
#define SVC2_VERS 1
#define SVC2_PROC_ADD 1)
#define SVC2_PROC_MULT 2
struct intpair {
u_short a;
u_short b;
};
typedef struct intpair intpair;
struct svc2_add_args {
int argument;
SVCXPRT *transp;
};
struct svc2_mult_args {
intpair mult_argument;
SVCXPRT *transp;
};
extern bool_t xdr_intpair();
#define NTHREADS_CONST 500
|
例 4-42 は、マルチスレッド・ユーザー・モードでのクライアントです。
#define _REENTRANT
#include <stdio.h>
#include <rpc/rpc.h>
#include <sys/uio.h>
#include <netconfig.h>
#include <netdb.h>
#include <rpc/nettype.h>
#include <thread.h>
#include "rpc_test.h"
void *doclient();
int NTHREADS;
struct thread_info {
thread_t client_id;
int client_status;
};
struct thread_info save_thread[NTHREADS_CONST];
main(argc, argv)
int argc;
char *argv[];
{
int index, ret;
int thread_status;
thread_t departedid, client_id;
char *hosts;
if (argc < 3) {
printf("Usage: do_operation [n] host¥n");
printf("¥twhere n is the number of threads¥n");
exit(1);
} else
if (argc == 3) {
NTHREADS = NTHREADS_CONST;
hosts = argv[1]; /* live_host */
} else {
NTHREADS = atoi(argv[1]);
hosts = argv[2];
}
for (index = 0; index < NTHREADS; index++){
if (ret = thr_create(NULL, NULL, doclient,
(void *) hosts, THR_BOUND, &client_id)){
printf("thr_create failed: return value %d", ret);
printf(" for %dth thread¥n", index);
exit(1);
}
save_thread[index].client_id = client_id;
}
for (index = 0; index < NTHREADS; index++){
if (thr_join(save_thread[index].client_id, &departedid,
(void *)
&thread_status)){
printf("thr_join failed for thread %d¥n",
save_thread[index].client_id);
exit(1);
}
save_thread[index].client_status = thread_status;
}
}
void *doclient(host)
char *host;
{
struct timeval tout;
enum clnt_stat test;
int result = 0;
u_short mult_result = 0;
int add_arg;
int EXP_RSLT;
intpair pair;
CLIENT *clnt;
if ((clnt = clnt_create(host, SVC2_PROG, SVC2_VERS, "udp"
==NULL) {
clnt_pcreateerror("clnt_create error: ");
thr_exit((void *) -1);
}
tout.tv_sec = 25;
tout.tv_usec = 0;
memset((char *) &result, 0, sizeof (result));
memset((char *) &mult_result, 0, sizeof (mult_result));
if (thr_self() % 2){
EXP_RSLT = thr_self() + 1;
add_arg = thr_self();
test = clnt_call(clnt, SVC2_PROC_ADD, (xdrproc_t) xdr_int,
(caddr_t) &add_arg, (xdrproc_t) xdr_int, (caddr_t) &result,
tout);
} else {
pair.a = (u_short) thr_self();
pair.b = (u_short) 1;
EXP_RSLT = pair.a * pair.b;
test = clnt_call(clnt, SVC2_PROC_MULT, (xdrproc_t)
xdr_intpair,
(caddr_t) &pair, (xdrproc_t) xdr_u_short,
(caddr_t) &mult_result, tout);
result = mult_result;
}
if (test != RPC_SUCCESS) {
printf("THREAD: %d clnt_call hav
thr_exit((void *) -1);
};
thr_exit((void *) 0);
}
|
例 4-43 は、マルチスレッド・ユーザー・モードのサーバー側を示します。マルチスレッドパフォーマンスは、関数 svc_getargs() が NULLPROC 以外の各手続きに呼び出される場合は、引き数 (この場合には xdr_void) がなくても改善されます。これは、マルチスレッド自動モードモードとマルチスレッドユーザーモードにおいてです。詳細は、rpc_svc_calls(3NSL) のマニュアルページを参照してください。
RPC マルチスレッド対応アプリケーションを作成する場合は常に、スレッドライブラリ内でリンクしなければなりません。コンパイルコマンドで -lthread を指定して、スレッドライブラリを最後にリンクするようにしなければなりません。
#define _REENTRANT
#include <stdio.h>
#include <rpc/rpc.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/uio.h>
#include <signal.h>
#include <thread.h>
#include "operations.h"
SVCXPRT *xprt;
void add_mult_prog();
void *svc2_add_worker();
void *svc2_mult_worker();
main(argc, argv)
int argc;
char **argv;
{
int transpnum;
char *nettype;
int mode = RPC_SVC_MT_USER;
if(rpc_control(RPC_SVC_MTMODE_SET,&mode) == FALSE){
printf(" rpc_control is failed to set AUTO mode¥n");
exit(0);
}
if (argc > 2) {
fprintf(stderr, "usage: %s [nettype]¥n", argv[0]);
exit(1);
}
if (argc == 2)
nettype = argv[1];
else
nettype = "netpath";
transpnum = svc_create(add_mult_prog, SVC2_PROG,
SVC2_VERS, nettype);
if (transpnum == 0) {
fprintf(stderr, "%s: cannot create %s service.¥n", argv[0],
nettype);
exit(1);
}
svc_run();
}
void add_mult_prog (rqstp, transp)
struct svc_req *rqstp;
SVCXPRT *transp;
{
int argument;
u_short mult_arg();
intpair mult_argument;
bool_t (*xdr_argument)();
struct svc2_mult_args *sw_mult_data;
struct svc2_add_args *sw_add_data;
int ret;
thread_t worker_id;
switch (rqstp->rq_proc){
case NULLPROC:
svc_sendreply(transp, xdr_void, (char *) 0);
svc_done(transp);
break;
case SVC2_PROC_ADD:
xdr_argument = xdr_int;
(void) memset((char *) &argument, 0, sizeof (argument));
if (!svc_getargs(transp, xdr_argument,
(char *) &argument)){
printf("problem with getargs¥n");
svcerr_decode(transp);
exit(1);
}
sw_add_data = (struct svc2_add_args *)
malloc(sizeof (struct svc2_add_args));
sw_add_data->transp = transp;
sw_add_data->argument = argument;
if (ret = thr_create(NULL, THR_MIN_STACK + 16 * 1024,
svc2_add_worker, (void *) sw_add_data, THR_DETACHED,
printf("SERVER: thr_create failed:");
printf(" return value %d", ret);
printf(" for add thread¥n");
exit(1);
}
break;
case SVC2_PROC_MULT:
xdr_argument = xdr_intpair;
(void) memset((char *) &mult_argument, 0,
sizeof (mult_argument));
if (!svc_getargs(transp, xdr_argument,
(char *) &mult_argument)){
printf("problem with getargs¥n");
svcerr_decode(transp);
exit(1);
}
sw_mult_data = (struct svc2_mult_args *)
malloc(sizeof (struct svc2_mult_args));
sw_mult_data->transp = transp;
sw_mult_data->mult_argument.a = mult_argument.a;
sw_mult_data->mult_argument.b = mult_argument.b;
if (ret = thr_create(NULL, THR_MIN_STACK + 16 * 1024,
svc2_mult_worker, (void *) sw_mult_data, THR_DETACHED,
&worker_id)){
printf("SERVER: thr_create failed:");
printf("return value %d", ret);
printf("for multiply thread¥n");
exit(1);
break;
default:
svcerr_noproc(transp);
svc_done(transp);
break;
}
}
u_short mult_arg();
int add_one();
void *svc2_add_worker(add_arg)
struct svc2_add_args *add_arg;
{ int *result;
bool_t (*xdr_result)();
xdr_result = xdr_int;
result = *malloc(sizeof (int));
*result = add_one(add_arg->argument);
if (!svc_sendreply(add_arg->transp, xdr_result,
(caddr_t) result)){
printf("sendreply failed¥n");
svcerr_systemerr(add_arg->transp);
svc_done(add_arg->transp);
thr_exit((void *) -1);
}
svc_done(add_arg->transp);
thr_exit((void *) 0);
}
void *svc2_mult_worker(m_arg)
struct svc2_mult_args *m_arg;
{
u_short *result;
bool_t (*xdr_result)();
xdr_result = xdr_u_short;
result = (u_short *) malloc(sizeof (u_short));
*result = mult_arg(&m_arg->mult_argument);
if (!svc_sendreply(m_arg->transp, xdr_result,
(caddr_t) result)){
printf("sendreply failed¥n");
svcerr_systemerr(m_arg->transp);
svc_done(m_arg->transp);
thr_exit((void *) -1);
}
svc_done(m_arg->transp);
thr_exit((void *) 0);
}
u_short mult_arg(pair)
intpair *pair;
{
u_short result;
result = pair->a * pair->b;
return (result);}
int add_one(arg)
int arg;
{
return (++arg);
}
|