UNIX では、コマンドの終了値は、0 が正常終了を意味します。
従って、プログラムが終了するときは
exit(終了値)
に正しい終了値を設定する必要があります。
終了値を知るには、以下のようにします。
% echo $status [csh の場合] $ echo $? [sh/ksh の場合]
通常、システムコールなどからエラーで戻り、処理を続行できないときは、 その戻り値を 終了値とします。 そのようにすれば、終了値からエラーの原因を知ることができます。
システムコールからのエラー番号は通常 /usr/include/sys/errno.h に定義されています。
エラー番号からエラーメッセージを取得するには、以下のようにします。
char * = strerror(エラー番号);
システムコールから戻されるエラー番号から、 エラーメッセージを取得するプログラム err.c です。
/* Function : output error message of system_call error Usage : err ERR_NO err Start_ERR_NO End_ERR_NO */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> int start,end; void usage(int no) { printf("Usage : err ERR_NO [TO_ERR_NO]\n"); exit(no); } int main(int argc,char *argv[]) { int i; getarg(argc,argv); for (i=start; i<=end; i++) { printf("%3d] %s\n",i,strerror(i)); } exit(0); } int getarg(int argc,char *argv[]) { if (argc == 1) { usage(EINVAL); } if (argc == 2) { start=atoi(argv[1]); end =start; } else if (argc == 3) { start=atoi(argv[1]); end =atoi(argv[2]); } else { usage(EINVAL); } if ((start > 0) && (start<0xffff)) { if ((end >= start) && (end <0xffff)) return 0; } usage(EINVAL); }
シグナルを送信され結果として終了すると、 シグナル一覧表 に明記されている終了値が設定されます。
上記事項を確認するために、 以下は自分自身に指定したシグナルを送るプログラム sig.c です。
/* sig.c -- send signal to myself */ #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <signal.h> char *menu[]={ "Which SIGNAL do you want to send = ?\n", " 1. SIGHUP Exit status=129\n", " 2. SIGINT Exit status=130\n", " 3. SIGQUIT Core status=131\n", " 4. SIGILL Core status=132\n", " 5. SIGTRAP Core status=133\n", " 6. SIGABRT Core status=134\n", " 7. Emulation Trap Core status=135\n", " 8. Floating exception Core status=136\n", " 9. Kill Exit status=137\n", " 10. Bus error Core status=138\n", " 11. Segmentation fault Core status=139\n", " 12. SIGSYS Core status=140\n", " 13. SIGPIPE Exit status=141\n", " 14. SIGALRM Exit status=142\n", " 15. SIGTERM Exit status=143\n", " 16. SIGUSR1 Exit status=144\n", " 17. SIGUSR2 Exit status=145\n", " 18. SIGCHLD Igno status=146\n", " 19. SIGPWR Igno status=147\n", " 20. SIGWINCH Igno status=148\n", " 21. SIGURG Igno status=149\n", " 22. SIGPOLL Exit status=150\n", " 23. SIGSTOP Stop status=151\n", " 24. SIGTSTP Stop status=152\n", " 25. SIGCONT Igno status=153\n", " 26. SIGTTIN Stop status=154\n", " 27. SIGTTOU Stop status=155\n", " 28. SIGVTALRM Exit status=156\n", " 29. SIGPROF Exit status=157\n", " 30. SIGXCPU Core status=158\n", " 31. SIGXFSZ Core status=159\n", " 100. Quit \n", }; #define SZ_MENU (sizeof(menu)/sizeof(char *)) int main(int argc,char *argv[]) { char cp; int i,pno,inpno,dum,ret; for (;;) { for (i=0; i<SZ_MENU; i++) printf(menu[i]); inpno = scanf("%d",&pno); if (! inpno) { printf("Input error !!\n\n"); for (;;) { dum = getchar(); if (dum == '\n') break; } continue; } if ((pno >0) && (pno <100)) { ret = kill( getpid(),pno); if (ret) exit(errno); } else exit(0); } }
pthread を3つ作ります。
threadTwo,threadThree は、メッセージを表示して終わりますが、 sigint スレッドは、CNTL_C を入力されるのを待っています。
/******************************************************************** compile with -D_POSIX_PTHREAD_SEMANTICS switch; required by sigwait() sigint thread handles delivery of signal. uses sigwait() to wait for SIGINT signal. ********************************************************************/ #include <pthread.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <synch.h> static void *threadTwo(void *); static void *threadThree(void *); static void *sigint(void *); sigset_t signalSet; void * main(void) { pthread_t t,t2,t3; thr_setconcurrency(3); sigfillset ( &signalSet ); /* * Block signals in initial thread. New threads will * inherit this signal mask. */ pthread_sigmask ( SIG_BLOCK, &signalSet, NULL ); printf("Creating threads\n"); /* POSIX thread create arguments: * thr_id, attr, strt_func, arg */ pthread_create(&t, NULL, sigint, NULL); pthread_create(&t2, NULL, threadTwo, NULL); pthread_create(&t3, NULL, threadThree, NULL); printf("##################\n"); printf("press CTRL-C to deliver SIGINT to sigint thread\n"); printf("##################\n"); thr_exit((void *)0); } static void * threadTwo(void *arg) { printf("hello world, from threadTwo [tid: %d]\n", pthread_self()); printf("threadTwo [tid: %d} is now complete and exiting\n", pthread_self()); thr_exit((void *)0); } static void * threadThree(void *arg) { printf("hello world, from threadThree [tid: %d]\n", pthread_self()); printf("threadThree [tid: %d} is now complete and exiting\n", pthread_self()); thr_exit((void *)0); } void * sigint(void *arg) { int sig; int err; printf("thread sigint [tid: %d] awaiting SIGINT\n", pthread_self()); /* use POSIX sigwait() -- 2 args * signal set, signum */ err = sigwait ( &signalSet, &sig ); /* test for SIGINT; could catch other signals */ if (err || sig != SIGINT) abort(); printf("\nSIGINT signal %d caught by sigint thread [tid: %d]\n", sig, pthread_self()); thr_exit((void *)0); }
次の例は、少し複雑です。
unix のスレッド関数は、SVR5 系と POSIX 系の2種類あります。 以下の thd.c では、それぞれの関数を使えるように、 条件付コンパイルができるようになっています。
このプログラムは、最大10のスレッドを生成し、その時刻を格納します。 そして、スレッドが終了するとその時刻を格納します。 すべてのスレッドが終了したら、各スレッドの開始時刻と終了時刻を表示します。
/* thd.c -- test program for thread Switch SVR5 - UNIX SVR5 thread POSIX - POSIX thread */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include <sys/signal.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <errno.h> #ifdef SVR5 #include <sys/unistd.h> #include <thread.h> #include <synch.h> #endif #ifdef POSIX #include <unistd.h> #include <pthread.h> #define thread_t pthread_t #define mutex_t pthread_mutex_t #define mutex_lock pthread_mutex_lock #define mutex_unlock pthread_mutex_unlock #endif #define min(a,b) ((a)>(b)?(b):(a)) #define SZ_STACK (128*1024L) #define MAX_TIMESTR 26 #define MAX_PRIO 127 #define MAX_SECS 10 #define MAX_LOOP 10 #define MAX_LOOP2 100 #define MAX_THREADS 10 void * sb(void *); static void * (*fun[])(void *)={sb,sb,sb,sb,sb,sb,sb,sb}; #define SZ_THREADS (sizeof(fun)/sizeof(void *)) #define NO_THREADS (min(MAX_THREADS,SZ_THREADS)) static thread_t thd_id[MAX_THREADS]; static int arginfo[MAX_THREADS],prio[MAX_THREADS], slptm [MAX_THREADS] ; static time_t start_tm[MAX_THREADS],end_tm[MAX_THREADS]; static char *info[]={ "AAA- 0","BBB- 1","CCC- 2","DDD- 3","EEE- 4","FFF- 5", "GGG- 6","HHH- 7","III- 8","JJJ- 9","KKK-10","LLL-11"}; mutex_t mutex; int thdno; #ifdef POSIX pthread_mutexattr_t attr; #endif main(int argc,char *argv[]) { int i,rtn,stk_size; void *status; thread_t *thd = &thd_id[0]; caddr_t addr; char *start,*end,str[MAX_TIMESTR]; time_t start_m,end_m; /* 1. get general information */ getinfo(); time(&start_m); mutexInit(); /* 2. set thread conditions and start */ for (i=0; i<NO_THREADS; i++) { prio [i] = get_prio(); slptm [i] = get_sec(); arginfo[i] = i; stk_size = SZ_STACK*(i+1); rtn = createThd(stk_size,fun[i],&arginfo[i],thd); thd++; } /* 3. wait to end executing of thread */ joinThd(); time(&end_m); /* 4. print elapse time */ start = ctime(&start_m); start[24] = ' '; strcpy(str,start); end = ctime(&end_m); end[24] = ' '; printf("\n TTL : %s - %s\n",str,end); printf("---------- ---------------------------------------------------\n"); printf(" NO:PRI:SL: Start time - End time\n"); for (i=0; i<NO_THREADS; i++) { start = ctime(&start_tm[i]); start[24] = ' '; strcpy(str,start); end = ctime(&end_tm[i]); end[24] = ' '; printf(" %2d:%3d:%2d: %s - %s\n",i,prio[i],slptm[i],str,end); } } void * sb(void *no) { int i,*n,rtn,priority,secs; stack_t stk; long tmp1,tmp2; thread_t tid; setThdno(1); n = (int *) no; tid = thd_id[*n]; time(&start_tm[*n]); #ifdef SVR5 setPriority(tid,prio[*n]); rtn = thr_stksegment(&stk); if (! rtn) { thr_getprio(tid,&priority); printf("New %d_thread start : %s \n",*n,info[*n]); fflush(stdout); } #endif sleep(slptm[*n]); for (i=0; i<MAX_LOOP; i++) { printf("%s no=%d i=%d\n",info[*n],*n,i); fflush(stdout); } for (i=0,tmp1=MAX_LOOP2; i<MAX_LOOP2; i++) { tmp2 = tmp1 * i; } time(&end_tm[*n]); setThdno(-1); return no; } int mutexInit() { int err; thdno = 0; #ifdef SVR5 err = mutex_init(&mutex,USYNC_THREAD,0); #endif #ifdef POSIX /* int pthread_mutexattr_init( pthread_mutexattr_t *attr); int pthread_mutex_init( pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); */ err = pthread_mutexattr_init(&attr); if (err) thd_exit("mutexInit:pthread_mutexattr_init",err); err = pthread_mutex_init(&mutex,&attr); #endif /* POSIX */ if (err) thd_exit("mutexInit:pthread_mutex_init",err); } int mutexLock() { int err; #ifdef POSIX for (;;) { err = pthread_mutex_trylock(&mutex); if (! err ) break; if (err != EBUSY) break; } if (err) thd_exit("mutextryLock",err); #else err = mutex_lock(&mutex); if (err) thd_exit("mutexLock",err); #endif } int mutexUnlock() { int err; err = mutex_unlock(&mutex); if (err) thd_exit("mutexUnlock",err); } int thd_exit(char *fname,int err) { printf("%s : %s\n",fname,strerror(err)); exit(err); } int get_prio() { return (get_rand() % MAX_PRIO); } int get_sec() { return (get_rand() % MAX_SECS); } int get_rand() { static int start=0; if (! start) { srand(100); start++; } return (rand()); } #ifdef SVR5 int setPriority(thread_t tid,int prio) { thr_setprio(tid,prio); } #endif int getThdno() { printf("getThdno : thread no=%d\n",thdno); return thdno; } int setThdno(int no) { mutexLock(); thdno += no; printf("setThdno : thread no=%d\n",thdno); mutexUnlock(); } int createThd(int stk_size,void *fun(void *),int arginfo[],thread_t *thd) { int err; #ifdef SVR5 return thr_create(NULL,stk_size,fun,(void *)(arginfo),NULL,thd); #endif #ifdef POSIX /* int pthread_create( pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg); */ err = pthread_create(thd,NULL,fun,(void *)(arginfo)); if (err) thd_exit("createThd:pthread_create",err); return err; #endif } int joinThd() { int i,err; void *val[MAX_THREADS]; for (i=0; i<NO_THREADS; i++) { #ifdef SVR5 err = thr_join(thd_id[i],NULL,&val[i]); #endif #ifdef POSIX /* int pthread_join( pthread_t thread, void **value_ptr); */ err = pthread_join(thd_id[i],&val[i]); #endif if (err) thd_exit("joinThd:pthread_join",err); } return err; } int getinfo() { #ifdef HP_UX printf("Running CPU is %ld and kernel is %ld mode\n", sysconf(_SC_CPU_VERSION),sysconf(_SC_KERNEL_BITS)); #else printf("Cpu no=%d online Cpu=%d\n", sysconf(_SC_NPROCESSORS_CONF),sysconf(_SC_NPROCESSORS_ONLN)); #endif fflush(stdout); }
Makefile の内容 CC_SUN = /usr/ucb/cc CC_DEC = /usr/bin/cc LIBS_SUN = -lthread LIBS_DEC = -lpthread LIBS_IBM = -lpthreads CFLAGS_SUN = -DSVR5 -I/usr/include -lthread -c -g CFLAGS_DEC = -DPOSIX -I/usr/include -thread -c -g CFLAGS_POSIX = -DPOSIX -I/usr/include -lpthread -c -g CFLAGS_AIX = -DPOSIX -I/usr/include -c -g CFLAGS_HP = -DPOSIX -DHP_UX -I/usr/include -lpthread -c -g TAGS = thd SRCS = $(TAGS).c OBJS = $(TAGS).o HDRS = TAGS: $(SRCS) $(HDRS) $(CC) $(CFLAGS) -c $(SRCS) $(CC) -o $(TAGS) $(OBJS) $(LDFLAGS) svr5: $(SRCS) $(HDRS) $(CC_SUN) $(CFLAGS_SUN) $(SRCS) $(CC_SUN) -o $(TAGS) $(OBJS) $(LIBS_SUN) posixDEC: $(SRCS) $(HDRS) $(CC_DEC) $(CFLAGS_DEC) $(SRCS) $(CC_DEC) -o $(TAGS) $(OBJS) $(LIBS_DEC) posixSUN: $(SRCS) $(HDRS) $(CC_SUN) $(CFLAGS_POSIX) $(SRCS) $(CC_SUN) -o $(TAGS) $(OBJS) $(LIBS_DEC) posixAIX:$(SRCS) $(HDRS) $(CC_DEC) $(CFLAGS_AIX) $(SRCS) $(CC_DEC) -o $(TAGS) $(OBJS) -L/usr/lib $(LIBS_IBM) posixHP:$(SRCS) $(HDRS) $(CC_DEC) $(CFLAGS_HP) $(SRCS) $(CC_DEC) -o $(TAGS) $(OBJS) -L/usr/lib $(LIBS_DEC) clean: rm -rf *.o $(TAGS) core