C プログラミング

  1. コマンドの終了値
    1. コマンドの終了値1
    2. プログラム1
    3. コマンドの終了値2
    4. プログラム2
  2. スレッド・プログラミング
  3. C 言語でのコーディング規約

コマンドの終了値

コマンドの終了値1

UNIX では、コマンドの終了値は、0 が正常終了を意味します。 従って、プログラムが終了するときは
exit(終了値) に正しい終了値を設定する必要があります。

終了値を知るには、以下のようにします。

   % echo $status         [csh     の場合]
   $ echo $?              [sh/ksh  の場合] 

通常、システムコールなどからエラーで戻り、処理を続行できないときは、 その戻り値を 終了値とします。 そのようにすれば、終了値からエラーの原因を知ることができます。

システムコールからのエラー番号は通常 /usr/include/sys/errno.h に定義されています。

エラー番号からエラーメッセージを取得するには、以下のようにします。

   char * = strerror(エラー番号); 

プログラム1

システムコールから戻されるエラー番号から、 エラーメッセージを取得するプログラム 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); 
} 

コマンドの終了値2

シグナルを送信され結果として終了すると、 シグナル一覧表 に明記されている終了値が設定されます。

プログラム2

上記事項を確認するために、 以下は自分自身に指定したシグナルを送るプログラム 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


【 関連項目 】

strerror(3C),getpid(2),kill(2),intro(2)

【 関連リンク 】

【 参考書 】

【 注意事項 】