マルチスレッドユーザーモードでは、サービス手続きは、戻しの前に svc_done() を呼び出さなければなりません。svc_done() は、クライアント要求が指定のサービストランスポートハンドルに向けたサービスに割り当てたリソースを解放しなければなりません。この機能は、クライアント要求がサービスされた後、あるいは応答の送信を妨げたエラーまたは異常な状態の後に呼び出されます。svc_done() が呼び出された後に、サービストランスポートハンドルは、サービス手続きによって参照されるべきではありません。次の例は、マルチスレッドユーザーモードでのサーバーを示します。
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 |
次の例は、マルチスレッドユーザーモードでのクライアントです。
#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); }
引数がない場合であっても、関数 svc_getargs() が NULLPROC 以外の各手続きに呼び出されるようにすれば、マルチスレッドのパフォーマンスが改善されます。この例では、xdr_void を使用できます。これは、マルチスレッド自動モードとマルチスレッドユーザーモードのどちらにも当てはまります。詳細は、rpc_svc_calls(3NSL) のマニュアルページを参照してください。
RPC マルチスレッド対応アプリケーションを作成する場合は常に、スレッドライブラリ内でリンクしなければなりません。スレッドライブラリは、コマンド行で最後にリンクする必要があります。コンパイルコマンドに -lthread オプションを指定します。