博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
进程间通信--信号(进程间通信唯一的异步方式)
阅读量:4294 次
发布时间:2019-05-27

本文共 7236 字,大约阅读时间需要 24 分钟。

一、信号的介绍
信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式。
信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了那些系统事件。
如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递个它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞取消时才被传递给进程。
二、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.\n");
  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.\n");
  28.             sleep(1);
  29.         }
  30.     
  31.     }else{
  32.         
  33.         for(i = 0;i < 5;i ++)
  34.         {
  35.             printf("Father loop.\n");
  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.\n");
  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",n);
  19.     
  20.     sleep(2);
  21.     n = alarm(5);
  22.     printf("n = %d.\n",n);
  23.     
  24.     while(1)
  25.     {
  26.         printf("count = %d.\n", ++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.\n");
  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.\n");
  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.\n",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",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.\n",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].\n",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.\n");
  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.\n");
  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.\n",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",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.\n",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].\n",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) |
0

上一篇:

下一篇:

相关热门文章
给主人留下些什么吧!~~
评论热议

转载地址:http://xsuws.baihongyu.com/

你可能感兴趣的文章
Could not find a storyboard named 'Main' in bundle NSBundle
查看>>
CocoaPods安装和使用教程
查看>>
Beginning Auto Layout Tutorial
查看>>
block使用小结、在arc中使用block、如何防止循环引用
查看>>
iPhone开发学习笔记002——Xib设计UITableViewCell然后动态加载
查看>>
iOS开发中遇到的问题整理 (一)
查看>>
Swift code into Object-C 出现 ***-swift have not found this file 的问题
查看>>
为什么你的App介绍写得像一坨翔?
查看>>
RTImageAssets插件--@3x可自动生成@2x图片
查看>>
iOS开发的一些奇巧淫技
查看>>
常浏览的博客和网站
查看>>
Xcode 工程文件打开不出来, cannot be opened because the project file cannot be parsed.
查看>>
点击button实现Storyboard中TabBar Controller的tab切换
查看>>
Xcode 的正确打开方式——Debugging
查看>>
打包app出现的一个问题
查看>>
iOS在Xcode6中怎么创建OC category文件
查看>>
Expanding User-Defined Runtime Attributes in Xcode with Objective-C
查看>>
iOS7 UITabBar自定义选中图片显示为默认蓝色的Bug
查看>>
提升UITableView性能-复杂页面的优化
查看>>
25 iOS App Performance Tips & Tricks
查看>>