• 进程间通信--信号(进程间通信唯一的异步方式)


    一、信号的介绍

    信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式。


    信号能够直接进行用户空间进程和内核进程之间的交互,内核进程也能够利用它来通知用户空间进程发生了那些系统事件。

    假设该进程当前并未处于运行态,则该信号就由内核保存起来,直到该进程恢复运行再传递个它;假设一个信号被进程设置为堵塞。则该信号的传递被延迟,直到其堵塞取消时才被传递给进程。

    二、linux操作系统支持的信号

    A. kill  -l



    B.经常使用信号的含义





    三、信号的产生

    A.用户在终端按下某些键时,终端驱动程序会发送信号给前台进程,比如ctr+c产生SIGINT,  ctr + 产生SIGQUI信号。ctr + z产生SIGTSTP。


    B.硬件异常产生信号,这些条件由硬件检測到并通知内核,然后内核向当前进程发送适当的信号。比如当前进程运行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。

    再比方当前进程訪问了非法内存地址,MMU会产生异常。内核将这个异常解释为SIGSEGV信号发送给当前进程 。


    C.一个进程调用int kill(pid_t pid,int sig)函数能够给还有一个进程发送信号

    D.能够用kill命令给某个进程发送信号,假设不明白指定信号则发送SIGTERM信号,该信号的默认处理动作是终止进程。

    E.当内核检測到某种软件条件发生时也能够通过信号通知进程,比如闹钟超时产生SIGALRM信号,向读端已关闭的管道写数据时产生SIGPIPE信号。

    四、进程对信号的处理

    A.忽略此信号
    B.运行该信号的默认处理动作
    C.提供一个信号处理函数,要求内核在处理该信号时切换到用户态运行这个处理函数,这样的方式成为捕捉(Catch)一个信号。
     

    五、相关信号API

    A.通过系统调用向一个指定的进程发送信号



    參数说明:
    第一个參数:指定发送信号的接收线程
    第二个參数:信号的signum

    案例一、
    父进程从终端输入signum,然后发给子进程


    点击(此处)折叠或打开

    1. #include <stdio.h>
    2. #include <sys/types.h>
    3. #include <signal.h>
    4. #include <stdlib.h>

    5. int main()
    6. {
    7.     int pid;

    8.     if((pid = fork()) < 0)
    9.     {
    10.     
    11.         perror("Fail to fork");
    12.         exit(EXIT_FAILURE);
    13.     
    14.     }else if(pid == 0){
    15.         
    16.         while(1);
    17.     
    18.     }else{
    19.         
    20.         int signum;
    21.         
    22.         while(scanf("%d",&signum) == 1)
    23.         {
    24.             kill(pid,signum);
    25.             system("ps -aux | grep a.out");
    26.         }
    27.     }

    28.     return 0;
    29. }

    运行结果例如以下:



    B.捕捉一个信号



    相应的API



    其原型:



    我们一般都是用第一个,也就是通过typedef改写过的。


    注意:signal函数我一般觉得其是向内核注冊当前进程收到信号的处理的方式。
    signal(SIGINT,handler);


    參数说明:

    signum  :  指定信号
    handler  :  SIG_IGN忽略该信号,SIG_DFL採用系统默认方式处理信号,自己定义的信号处理函数指针。

    案例探究:

    通过异步方式,给子进程收尸

    注意:子进程在终止时会给父进程发SIGCHLD,该信号的默认处理动作是忽略。父进程能够自己定义SIGCHLD信号的处理函数,这样父进程仅仅须要专心处理自己的工作。不必关心子进程了。子进程终止时会通知父进程。父进程在信号处理函数中调用wait清理子进程就可以。



    点击(此处)折叠或打开

    1. #include <stdio.h>
    2. #include <signal.h>
    3. #include <unistd.h>
    4. #include <stdlib.h>

    5. void child_exit_handler(int signum)
    6. {
    7.     if(signum == SIGCHLD)
    8.     {
    9.         printf("Child exit. ");
    10.         wait(NULL);
    11.     }
    12. }

    13. int main()
    14. {
    15.     int pid;
    16.     int i = 0;

    17.     //想内核注冊,处理 SIGCHLD信号的方式
    18.     signal(SIGCHLD,child_exit_handler);

    19.     if((pid = fork()) < 0)
    20.     {
    21.         perror("Fail to fork");
    22.         exit(EXIT_FAILURE);

    23.     }else if(pid == 0){
    24.         
    25.         for(i = 0;i < 5;i ++)
    26.         {
    27.             printf("child loop. ");
    28.             sleep(1);
    29.         }
    30.     
    31.     }else{
    32.         
    33.         for(i = 0;i < 5;i ++)
    34.         {
    35.             printf("Father loop. ");
    36.             sleep(2);
    37.         }

    38.     }

    39.     exit(EXIT_SUCCESS);
    40. }

    C.闹钟函数alarm



    larm()也称为闹钟函数,它能够在进程中设置一个定时器。当定时器指定的时间到时。内核就向进程发送SIGALARM信号。

    seconds:指定的秒数,假设參数seconds为0。则之前设置的闹钟会被取消。并将剩下的时间返回。

    成功:假设调用此alarm()前,进程中已经设置了闹钟时间,则放回上一个闹钟时间的剩余时间,否则返回0。

    alarm(100);
    ........

    ......

    alarm(5);

    出错:-1

    案例探究:


    点击(此处)折叠或打开

    1. #include <stdio.h>
    2. #include <signal.h>
    3. #include <stdlib.h>

    4. void handler(int signum)
    5. {
    6.     if(signum == SIGALRM)
    7.     {
    8.         printf("Recv SIGALARM. ");
    9.     }

    10.     exit(EXIT_SUCCESS);
    11. }

    12. int main()
    13. {
    14.     int count = 0;
    15.     int n = 0;

    16.     signal(SIGALRM,handler);

    17.     n = alarm(10);

    18.     printf("n = %d. ",n);
    19.     
    20.     sleep(2);

    21.     n = alarm(5);

    22.     printf("n = %d. ",n);
    23.     
    24.     while(1)
    25.     {
    26.         printf("count = %d. ", ++count);
    27.         sleep(1);
    28.     }

    29.     return 0;
    30. }
    运行结果例如以下:



    案例二、综合案例

    使用FIFO实现clientA与clientB之间聊天
    A.输入quit后,两个进程退出
    B.假设在20秒内。没有等到还有一端发来的消息,则觉得对方已不在。此时终止。

    clientA:


    点击(此处)折叠或打开

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <signal.h>
    4. #include <sys/types.h>
    5. #include <sys/stat.h>
    6. #include <errno.h>
    7. #include <string.h>
    8. #include <fcntl.h>

    9. #define MAX 100

    10. void signal_handler(int signum)
    11. {
    12.     static int flag = 0;

    13.     switch(signum)
    14.     {
    15.         case SIGALRM:
    16.             if(flag == 0)
    17.             {
    18.                 printf("The people is leaving,the system is closed in 10 seconds
    19.                         and you can input 'ctrl + c' cancel. ");
    20.                 alarm(10);
    21.             }else{
    22.                 
    23.                 kill(getppid(),SIGKILL);
    24.                 usleep(500);
    25.                 exit(EXIT_SUCCESS);
    26.             }

    27.             flag = 1;            
    28.             break;

    29.         case SIGINT:
    30.             printf("The alarm is cancel. ");
    31.             alarm(0);
    32.             break;
    33.     }

    34. }

    35. int child_recv_fifo(char *fifo_name)
    36. {
    37.     int n,fd;
    38.     char buf[MAX];

    39.     if((fd = open(fifo_name,O_RDONLY)) < 0)
    40.     {
    41.         fprintf(stderr,"fail to open %s : %s. ",fifo_name,strerror(errno));
    42.         return -1;
    43.     }

    44.     signal(SIGALRM,signal_handler);
    45.     signal(SIGINT,signal_handler);
    46.     alarm(15);//璁剧疆瀹氭椂鍣?    
    47.     while(1)
    48.     {
    49.         n = read(fd,buf,sizeof(buf));
    50.         buf[n] = '0';

    51.         printf("Read %d bytes : %s. ",n,buf);

    52.         if(strncmp(buf,"quit",4) == 0 || n == 0)
    53.         {
    54.             kill(getppid(),SIGKILL);
    55.             usleep(500);
    56.             exit(EXIT_SUCCESS);
    57.         }

    58.         alarm(15);
    59.     }

    60.     return 0;
    61. }

    62. int father_send_fifo(char *fifo_name,int pid)
    63. {
    64.     int n,fd;
    65.     char buf[MAX];

    66.     if((fd = open(fifo_name,O_WRONLY)) < 0)
    67.     {
    68.         fprintf(stderr,"Fail to open %s : %s. ",fifo_name,strerror(errno));
    69.         return -1;
    70.     }

    71.     signal(SIGINT,SIG_IGN);

    72.     while(1)
    73.     {
    74.         getchar();
    75.         printf(">");

    76.         fgets(buf,sizeof(buf),stdin);
    77.         buf[strlen(buf)-1] = '0';

    78.         write(fd,buf,strlen(buf));

    79.         if(strncmp(buf,"quit",4) == 0)
    80.         {
    81.             kill(pid,SIGKILL);
    82.             usleep(500);
    83.             exit(EXIT_SUCCESS);
    84.         }
    85.     }

    86.     return 0;
    87. }

    88. int main(int argc,char *argv[])
    89. {
    90.     int pid;

    91.     if(argc < 3)
    92.     {
    93.         fprintf(stderr,"usage %s argv[1]. ",argv[0]);
    94.         exit(EXIT_FAILURE);
    95.     }

    96.     if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)
    97.     {
    98.         perror("Fail to mkfifo");
    99.         exit(EXIT_FAILURE);
    100.     }

    101.     if(mkfifo(argv[2],0666) < 0 && errno != EEXIST)
    102.     {
    103.         perror("Fail to mkfifo");
    104.         exit(EXIT_FAILURE);
    105.     }
    106.     
    107.     if((pid = fork()) < 0)
    108.     {
    109.     
    110.         perror("Fail to fork");
    111.         exit(EXIT_FAILURE);
    112.     
    113.     }else if(pid == 0){
    114.         
    115.         child_recv_fifo(argv[2]);
    116.     
    117.     }else{

    118.         father_send_fifo(argv[1],pid);
    119.     }

    120.     exit(EXIT_SUCCESS);
    121. }

    client B


    点击(此处)折叠或打开

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <signal.h>
    4. #include <sys/types.h>
    5. #include <sys/stat.h>
    6. #include <errno.h>
    7. #include <string.h>
    8. #include <fcntl.h>

    9. #define MAX 100

    10. void signal_handler(int signum)
    11. {
    12.     static int flag = 0;

    13.     switch(signum)
    14.     {
    15.         case SIGALRM:
    16.             if(flag == 0)
    17.             {
    18.                 printf("The people is leaving,the system is closed in 10 seconds
    19.                         and you can input 'ctrl + c' cancel. ");
    20.                 alarm(10);
    21.             }else{
    22.                 
    23.                 kill(getppid(),SIGKILL);
    24.                 usleep(500);
    25.                 exit(EXIT_SUCCESS);
    26.             }

    27.             flag = 1;            
    28.             break;

    29.         case SIGINT:
    30.             printf("The alarm is cancel. ");
    31.             alarm(0);
    32.             break;
    33.     }

    34. }

    35. int child_recv_fifo(char *fifo_name)
    36. {
    37.     int n,fd;
    38.     char buf[MAX];

    39.     if((fd = open(fifo_name,O_RDONLY)) < 0)
    40.     {
    41.         fprintf(stderr,"fail to open %s : %s. ",fifo_name,strerror(errno));
    42.         return -1;
    43.     }

    44.     signal(SIGALRM,signal_handler);
    45.     signal(SIGINT,signal_handler);
    46.     alarm(15);//璁剧疆瀹氭椂鍣?

          

    47.     while(1)
    48.     {
    49.         n = read(fd,buf,sizeof(buf));
    50.         buf[n] = '0';

    51.         printf("Read %d bytes : %s. ",n,buf);

    52.         if(strncmp(buf,"quit",4) == 0 || n == 0)
    53.         {
    54.             kill(getppid(),SIGKILL);
    55.             usleep(500);
    56.             exit(EXIT_SUCCESS);
    57.         }

    58.         alarm(15);
    59.     }

    60.     return 0;
    61. }

    62. int father_send_fifo(char *fifo_name,int pid)
    63. {
    64.     int n,fd;
    65.     char buf[MAX];

    66.     if((fd = open(fifo_name,O_WRONLY)) < 0)
    67.     {
    68.         fprintf(stderr,"Fail to open %s : %s. ",fifo_name,strerror(errno));
    69.         return -1;
    70.     }

    71.     signal(SIGINT,SIG_IGN);

    72.     while(1)
    73.     {
    74.         getchar();
    75.         printf(">");

    76.         fgets(buf,sizeof(buf),stdin);
    77.         buf[strlen(buf)-1] = '0';

    78.         write(fd,buf,strlen(buf));

    79.         if(strncmp(buf,"quit",4) == 0)
    80.         {
    81.             kill(pid,SIGKILL);
    82.             usleep(500);
    83.             exit(EXIT_SUCCESS);
    84.         }
    85.     }

    86.     return 0;
    87. }

    88. int main(int argc,char *argv[])
    89. {
    90.     int pid;

    91.     if(argc < 3)
    92.     {
    93.         fprintf(stderr,"usage %s argv[1]. ",argv[0]);
    94.         exit(EXIT_FAILURE);
    95.     }

    96.     if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)
    97.     {
    98.         perror("Fail to mkfifo");
    99.         exit(EXIT_FAILURE);
    100.     }

    101.     if(mkfifo(argv[2],0666) < 0 && errno != EEXIST)
    102.     {
    103.         perror("Fail to mkfifo");
    104.         exit(EXIT_FAILURE);
    105.     }
    106.     
    107.     if((pid = fork()) < 0)
    108.     {
    109.     
    110.         perror("Fail to fork");
    111.         exit(EXIT_FAILURE);
    112.     
    113.     }else if(pid == 0){
    114.         
    115.         child_recv_fifo(argv[1]);
    116.     
    117.     }else{

    118.         father_send_fifo(argv[2],pid);
    119.     }

    120.     exit(EXIT_SUCCESS);
    121. }

    D.将进程挂起函数pause



    解释例如以下:



    案比例如以下:



    <script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
    阅读(31) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
  • 相关阅读:
    C# 字典 Dictionary 转 JSON 格式遍历
    jquery-easyui-tree异步树
    android 开发环境搭建
    解决android sdk 无法更新
    043——VUE中组件之使用.sync修饰符与computed计算属性实现购物车原理
    laravel中数据库迁移的使用:
    002PHP文件处理——文件处理 is_dir mkdir getcwd chdir rmdir
    001PHP文件处理——文件处理disk_total_space disk_free_space basename dirname file_exists filetype
    042——VUE中组件之子组件使用$on与$emit事件触发父组件实现购物车功能
    041——VUE中组件之pros数据的多种验证机制实例详解
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/7365765.html
  • Copyright © 2020-2023  润新知