zoukankan      html  css  js  c++  java
  • GNU FORK PTHREAD SIGNALS

    Linux程序设计入门 - fork, pthread, and signals 
    
      在UNIX程序设计中,学会fork及signal的运用,算是相当基本的功夫。  
     
       
      fork()及signal经常运用在daemon守护神这一类常驻程序,另外像 
       
      a4c.tty/yact/chdrv这些中文终端机程序也有用到,一般如 
       
      Mozilla/Apache/Squid等大程序几乎都一定会用到。  
     
       
      虽然在UNIX下的程序写作,对thread的功能需求并非很大,但thread在现代的 
       
      作业系统中,几乎都已经存在了。pthread是Linux上的thread函数库,如果您 
       
      要在Linux下撰写多线程序,例如MP3播放程序,熟悉pthread的用法是必要的。 
     
       
      pthread及signal都可以用一大章来讨论。在这里,我只谈及最简单及常用的技 
       
      巧,当您熟悉这些基本技巧的运用後,再找一些专门深入探讨pthread及signal 
       
      程序写作的书籍来研究。这些进阶的写法,用到的机会较少,将层次分明,学 
       
      习速度应该会比较快。  
     
     
       
      程序分歧fork() 
     
       
      fork()会产生一个与父程序相同的子程序,唯一不同之处在於其process 
       
      id(pid)。  
     
       
      如果我们要撰写守护神程序,或是例如网路伺服器,需要多个行程来同时提供 
       
      多个连线,可以利用fork()来产生多个相同的行程。  
     
       
      函数宣告 
     
       
      pid_t fork(void);  
       
      pid_t vfork(void);  
     
       
      返回值: 
     
       
      -1 : 失败。  
       
        0 : 子程序。  
       
      >0 : 将子程序的process id传回给父程序。  
     
       
      在Linux下fork()及vfork()是相同的东西。  
     
       
      范例一: fork.c 
     
       
      在这个范例中,我们示范fork()的标准用法。  
     
       
      #include <stdio.h>  
       
      #include <stdlib.h>  
       
      #include <unistd.h>  
     
       
      void main(void)  
       
      {  
       
        pid_t pid;  
     
       
        printf("hello
    ");  
       
        pid = fork();  
     
       
        switch (pid) {  
       
          case -1: printf("failure!
    "); break;  
       
          case  0: printf("I am child!
    "); break;  
       
          default: printf("my child is %d
    ",pid); break;  
       
        }  
       
        for (;;) { /* do something here */ }  
       
      }  
     
       
      编译: 
     
       
      gcc -o ex1 fork.c  
     
       
      执行结果: 
     
       
      ./ex1 &  
     
       
      hello  
       
      my child is 8650  
       
      I am child!  
     
       
      我们可以见到,使用fork(),可将一个程序分岐成两个。在分歧之前的程序码 
       
      只执行一次。  
     
       
      检验行程: 
     
       
      ps | grep ex1  
     
       
       8649  p0 R    0:40 ./ex1  
       
       8650  p0 R    0:40 ./ex1  
     
       
      8649是父程序的pid,8650则为子程序的pid。  
       
      您会需要用到"killall ex1"来杀掉两个行程。  
     
       
      范例二: daemon.c 
     
       
      在UNIX中,我们一般都利用fork(),来实作所谓的"守护神程序",也就是DOS中 
       
      所谓的"常驻程序"。一般的技巧是将父程序结束,而子程序便成为"守护神"。  
     
       
      这个范例中,示范一般标准的daemon写法。  
     
       
      #include <stdio.h>  
       
      #include <stdlib.h>  
       
      #include <unistd.h>  
     
       
      void main(void)  
       
      {  
       
        pid_t pid;  
     
       
        pid = fork();  
     
       
        if (pid>0) {  
       
          printf("daemon on duty!
    ");  
       
          exit(0);  
       
        } else  
       
        if (pid<0) {  
       
          printf("Can't fork!
    ");  
       
          exit(-1);  
       
        }  
     
       
        for (;;) {  
       
          printf("I am the daemon!
    ");  
       
          sleep(3);  
       
          /* do something your own here */  
       
        }  
     
       
      }  
     
       
      编译: 
     
       
      gcc -o ex2 daemon.c  
     
       
      执行结果: 
     
       
      ./ex2  
     
       
      daemon on duty!  
       
      I am the daemon!  
       
      接下来每三秒钟,都会出现一个"I am the daemon!"的讯息,这表示您的程序 
       
      已经"长驻"在系统中了。  
     
       
      检验行程: 
     
       
      ps | grep ex2  
     
       
      8753  p0 S    0:00 ./ex2  
     
       
      注意到在范例一中,我们下的指令为"./ex1 &",而在范例二中为"./ex2",没 
       
      有"&"符号。  
       
         
     
       
      范例三: lock.c 
     
       
      许多的时候,我们希望"守护神"在系统中只有一个,这时候会需要用到pid 
       
      lock的技巧。如果您注意到/var/run目录中的内容,您会发现到有许多的*.pid 
       
      档,观看其内容都是一些数字,这些数字其实就是该行程的pid。  
     
       
      #include <stdio.h>  
       
      #include <stdlib.h>  
       
      #include <unistd.h>  
     
       
      void main(void)  
       
      {  
       
        FILE *fp;  
       
        pid_t pid;  
     
        
       
          exit(-1);  
       
        }  
     
       
        act.sa_handler = quit;  
       
        act.sa_flags   = 0;  
       
        sigemptyset(&act.sa_mask);  
       
        sigaction(SIGTERM,&act,NULL);  
       
        sigaction(SIGHUP,&act,NULL);  
       
        sigaction(SIGINT,&act,NULL);  
       
        sigaction(SIGQUIT,&act,NULL);  
       
        sigaction(SIGUSR1,&act,NULL);  
       
        sigaction(SIGUSR2,&act,NULL);  
     
       
        for (;;) {  
       
          sleep(3);  
       
        }  
       
      }  
     
       
      编译: 
     
       
      gcc -o ex1 lock.c  
     
       
      执行 
     
       
      ./ex1  
     
       
      daemon on duty!  
     
       
      送信号 
     
       
      我们先找出该守护神程序的pid  
     
       
      PID=`cat /var/run/lock.pid`  
     
       
      接下来利用kill来送信号  
     
       
      kill $PID  
     
       
      Receive signal 15  
     
       
      程序将会结束,并且/var/run/lock.pid将会被删除掉,以便下一次daemon再启 
       
      动。注意到如果quit函数内,没有放exit(),程序 将永远杀不掉。  
     
       
      接下来送一些其它的信号试试看。  
       
      ./ex1  
       
      PID=`cat /var/run/lock.pid`  
       
      kill -HUP $PID  
     
       
      Receive signal 1  
     
       
      您可以自行试试  
       
      kill -INT $PID  
       
      kill -QUIT $PID  
       
      kill -ILL $PID  
       
      .  
       
      .  
       
      .  
       
      等等这些信号,看看他们的结果如何。  
     
       
      信号的定义 
     
       
      在/usr/include/signum.h中有各种信号的定义  
       
      #define SIGHUP          1       /* Hangup (POSIX).  */  
       
      #define SIGINT          2       /* Interrupt (ANSI).  */  
       
      #define SIGQUIT         3       /* Quit (POSIX).  */  
       
      #define SIGILL          4       /* Illegal instruction (ANSI).  */  
       
      #define SIGTRAP         5       /* Trace trap (POSIX).  */  
       
      #define SIGABRT         6       /* Abort (ANSI).  */  
       
      #define SIGIOT          6       /* IOT trap (4.2 BSD).  */  
       
      #define SIGBUS          7       /* BUS error (4.2 BSD).  */  
       
      #define SIGFPE          8       /* Floating-point exception (ANSI).  
       
      */  
       
      #define SIGKILL         9       /* Kill, unblockable (POSIX).  */  
       
      #define SIGUSR1         10      /* User-defined signal 1 (POSIX).  */ 
     
       
      #define SIGSEGV         11      /* Segmentation violation (ANSI).  */ 
     
       
      #define SIGUSR2         12      /* User-defined signal 2 (POSIX).  */ 
     
       
      #define SIGPIPE         13      /* Broken pipe (POSIX).  */  
       
      #define SIGALRM         14      /* Alarm clock (POSIX).  */  
       
      #define SIGTERM         15      /* Termination (ANSI).  */  
       
      #define SIGSTKFLT       16      /* ??? */  
       
      #define SIGCLD          SIGCHLD /* Same as SIGCHLD (System V).  */  
       
      #define SIGCHLD         17      /* Child status has changed (POSIX).  
       
      */  
       
      #define SIGCONT         18      /* Continue (POSIX).  */  
       
      #define SIGSTOP         19      /* Stop, unblockable (POSIX).  */  
       
      #define SIGTSTP         20      /* Keyboard stop (POSIX).  */  
       
      #define SIGTTIN         21      /* Background read from tty (POSIX).  
       
      */  
       
      #define SIGTTOU         22      /* Background write to tty (POSIX).  
       
      */  
       
      #define SIGURG          23      /* Urgent condition on socket (4.2 
       
      BSD).  */  
       
      #define SIGXCPU         24      /* CPU limit exceeded (4.2 BSD).  */  
       
      #define SIGXFSZ         25      /* File size limit exceeded (4.2 
       
      BSD).  */  
       
      #define SIGVTALRM       26      /* Virtual alarm clock (4.2 BSD).  */ 
     
       
      #define SIGPROF         27      /* Profiling alarm clock (4.2 BSD).  
       
      */  
       
      #define SIGWINCH        28      /* Window size change (4.3 BSD, Sun). 
       
        */  
       
      #define SIGPOLL         SIGIO   /* Pollable event occurred (System 
       
      V).  */  
       
      #define SIGIO           29      /* I/O now possible (4.2 BSD).  */  
       
      #define SIGPWR          30      /* Power failure restart (System V).  
       
      */  
       
      #define SIGUNUSED       31  
     
       
      函数宣告: 
     
       
      Signal Operators  
     
       
           int sigemptyset(sigset_t *set);  
       
           int sigfillset(sigset_t *set);  
       
           int sigaddset(sigset_t *set, int signum);  
       
           int sigdelset(sigset_t *set, int signum);  
       
           int sigismember(const sigset_t *set, int signum);  
     
       
      Signal Handling Functions  
     
       
           int sigaction(int signum,  const  struct  sigaction  *act,struct 
       
           sigaction *oldact);  
       
           int  sigprocmask(int  how,  const  sigset_t *set, sigset_t 
       
           *oldset);  
       
           int sigpending(sigset_t *set);  
       
           int sigsuspend(const sigset_t *mask);  
     
       
      Structure Signal Action  
       
      struct sigaction {  
       
                       void (*sa_handler)(int);  
       
                       sigset_t sa_mask;  
       
                       int sa_flags;  
       
                       void (*sa_restorer)(void);  
       
                   }  
       
         
     
     
     
       
      OK STATION, Webmaster, Brian Lin  
       
         
       
       
  • 相关阅读:
    lua 根据路径获取文件名
    python中的re模块
    正则表达式中的开头和结尾
    正则表达式匹配多个字符
    正则表达式中匹配单个字符
    正则表达式的作用
    gevent实现协程
    greenlet实现协程
    生成器的使用注意
    生成器实现斐波那契数列
  • 原文地址:https://www.cnblogs.com/unixshell/p/3337999.html
Copyright © 2011-2022 走看看