• 三十一、Linux 进程与信号——SIGCHLD 信号、kill和raise函数以及alarm函数


    31.1 SIGCHLD 信号

    • 子进程状态发生变化(子进程结束)产生该信号,父进程需要使用 wait 调用来等待子进程结束并回收它。
    • 避免僵尸进程
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <signal.h>
     4 #include <sys/wait.h>
     5 #include <unistd.h>
     6 
     7 void sig_handler(int signo)
     8 {
     9     printf("child process deaded, signo: %d
    ", signo);
    10 
    11     /** 当父进程捕获到 SIGCHLD 信号后要调用 wait
    12      * 函数去回收子进程,否则子进程会成为僵尸进程 */
    13     wait(0);
    14 }
    15 
    16 
    17 void out(int n)
    18 {
    19     int i;
    20     for(i = 0; i < n; i++) {
    21     
    22         printf("%d out %d
    ", getpid(), i); 
    23         sleep(2);
    24     }
    25 }
    26 
    27 int main(void)
    28 {
    29     if(signal(SIGCHLD, sig_handler)){
    30         perror("signal sigchld error");
    31     }
    32 
    33     pid_t pid = fork();
    34     if(pid < 0) {
    35         
    36         perror("fork error");
    37         exit(1);
    38     } else if(pid > 0) {
    39         /** parent process */ 
    40         out(100);
    41     } else {
    42         /** child process */
    43         out(10);
    44     }
    45 
    46     return 0;
    47 }

    31.2 信号发送

    • 除了内核和超级用户,并不是每个进程都可以向其他的进程发送信号
    • 一般的进程只能向具有相同 uid 和 gid 的进程发送信号,或向相同进程组中的其他进程发送信号
    • 常用的发送信号的函数由 kill()、raise()、alarm()、settitimer()、abort()等。

    31.2.1 kill() 函数 和 raise() 函数

    1 #include <signal.h>
    2 int kill(pid_t pid, int signo);
    • 函数功能:向指定的进程发送某一个信号
    • 函数参数:
      • pid:接受信号进程的 pid
        • pid > 0  将信号发给进程 ID 为 pid 的进程
        • pid == 0   将信号发给与发送进程同一进程组的所有进程       
        • pid < 0        将该信号发送给进程组 ID 等于 pid 的绝对值
        • pid == -1     将该信号发送给发送进程有权限向他们发送信号的系统上的所有进程
      • signo:要发送的信号值
    • 返回值:成功返回0,出错返回 -1
    • 说明:kill 函数将信号发送给进程或进程组
      • 0 为空信号,常用来检测特定的进程是否存在
    1 #include <signal.h>
    2 int raise(int signo);
    • 函数功能:向进程本身发送一个信号,相当于 kill(getpid(), sig)
    • 函数参数:
      • signo:要发送的信号值
    • 返回值:成功返回0,出错返回 -1
     1 #include <signal.h>
     2 #include <stdlib.h>
     3 #include <stdio.h>
     4 #include <unistd.h>
     5 
     6 #define KILLSELF    0
     7 
     8 /** 定义信号处理函数
     9  *  signo   进程捕获到的信号
    10  */
    11 void sig_handler(int signo)
    12 {
    13     printf("%d, %d occured
    ", getpid(), signo);
    14 }
    15 
    16 int main(void)
    17 {
    18     /** 向内核登记信号处理函数以及信号值 */
    19     if(signal(SIGTSTP, sig_handler) == SIG_ERR) {
    20         perror("signal sigtstp error");
    21     }
    22 
    23     if(signal(SIGINT, sig_handler) == SIG_ERR) {
    24         perror("signal sigint error");
    25     }
    26 
    27     if(signal(SIGUSR1, sig_handler) == SIG_ERR) {
    28         perror("signal usr1 error");
    29     }
    30 
    31     if(signal(SIGUSR2, sig_handler) == SIG_ERR) {
    32         perror("signal usr2 error");
    33     }
    34 /*
    35     if(signal(SIGKILL, SIG_IGN) == SIG_ERR) {
    36         perror("signal sigtstp error");
    37     }
    38 
    39     if(signal(SIGSTOP, SIG_IGN) == SIG_ERR) {
    40         perror("signal sigint error");
    41     }
    42 */
    43     int i = 0;
    44     while(i < 20) {
    45         printf("%d out %d
    ", getpid(), i++);
    46         if(i == 10) {
    47 #ifdef KILLSELF
    48             kill(getpid(), SIGKILL);
    49 #endif
    50             sleep(1);
    51         }
    52         sleep(1);
    53     }
    54 
    55     /** 向进程自己发送 SIGUSR1 和SIGUSR2 信号 */
    56     raise(SIGUSR1);
    57     kill(getpid(), SIGUSR2);
    58     return 0;
    59 }

    31.2.2 alarm() 函数

    1 #include <unistd.h>
    2 unsigned int alarm(unsigned int seconds);
    • 函数说明:
      • alarm 函数可设置定时器,当定时器超时,产生 SIGALRM 信号
      • 信号由内核产生,在指定的 seconds 秒之后,给进程本身发送一个 SIGALRM 信号。
      • 参数为 0,取消以前设置的定时器
    • 返回值:
      • 0 或以前设置的定时器时间余留秒数

        

     1 #include <signal.h>
     2 #include <unistd.h>
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 #include <math.h>
     6 
     7 void sig_handler(int signo)
     8 {
     9     if(SIGALRM == signo) {
    10         printf("clock time out
    ");
    11         alarm(5);    ///< 重新设置定时器(周期性的定时)
    12     }
    13 }
    14 
    15 void out_data(void)
    16 {
    17     int i = 1;
    18     while(i <= 20) {
    19         double d = drand48();
    20         printf("%-10d: %lf
    ", i++, d);
    21         if(i == 16) 
    22             alarm(0); ///< 取消定时器
    23         sleep(1);
    24     }
    25 }
    26 
    27 int main(void)
    28 {
    29     if(signal(SIGALRM, sig_handler) == SIG_ERR) {
    30         perror("signal sigalrm error");
    31     }
    32 
    33     // 设置定时器
    34     alarm(5);
    35     printf("begin running main
    ");
    36     out_data();
    37     printf("end running main
    ");
    38     return 0;
    39 }
  • 相关阅读:
    MySQL GROUP BY多个字段分组用法详解
    Linux下自动备份MySQL数据库并上传到远程FTP服务器
    mysql服务器主从数据库同步配置(转)
    centos上安装配置java WEB环境_java(转)
    Win7和Vista的安全机制对于应用程序读取配置文件相关操作的影响(虚拟重定向技术)
    firemonkey 手机屏幕自适应程序问题
    Delphi中无边框窗体应用程序使任务栏右键菜单有效的方法
    GetClass与RegisterClass的应用一例
    Delphi中的动态包,有详细建立包的步骤(答案很简单:因为包的功能强大)
    JS开发调试
  • 原文地址:https://www.cnblogs.com/kele-dad/p/10116587.html
Copyright © 2020-2023  润新知