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/n"); 
  
    pid = fork(); 
 
  
    switch (pid) { 
  
      case -1: printf("failure!/n"); break; 
  
      case  0: printf("I am child!/n"); break; 
  
      default: printf("my child is %d/n",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!/n"); 
  
      exit(0); 
  
    } else 
  
    if (pid<0) { 
  
      printf("Can't fork!/n"); 
  
      exit(-1); 
  
    } 
 
  
    for (;;) { 
  
      printf("I am the daemon!/n"); 
  
      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 
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值