进程间通信--信号(进程间通信唯一的异步方式)
一、信号的介绍
信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式。
信号能够直接进行用户空间进程和内核进程之间的交互,内核进程也能够利用它来通知用户空间进程发生了那些系统事件。
假设该进程当前并未处于运行态,则该信号就由内核保存起来,直到该进程恢复运行再传递个它;假设一个信号被进程设置为堵塞。则该信号的传递被延迟,直到其堵塞取消时才被传递给进程。
二、linux操作系统支持的信号
A. kill -l
![](/attachment/201205/30/26833883_1338368070RJZ9.png)
B.经常使用信号的含义
![](/attachment/201205/30/26833883_1338368118pO0w.png)
![](/attachment/201205/30/26833883_1338368141wW9t.png)
![](/attachment/201205/30/26833883_1338368388F4VC.png)
![](/attachment/201205/30/26833883_1338368443Z90f.png)
![](/attachment/201205/30/26833883_1338368070RJZ9.png)
B.经常使用信号的含义
![](/attachment/201205/30/26833883_1338368118pO0w.png)
![](/attachment/201205/30/26833883_1338368141wW9t.png)
三、信号的产生
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.通过系统调用向一个指定的进程发送信号
![](/attachment/201205/30/26833883_13383681747UiI.png)
运行结果例如以下:
![](/attachment/201205/30/26833883_1338368246TAub.png)
B.捕捉一个信号
![](/attachment/201205/30/26833883_1338368273dQ8B.png)
相应的API
![](/attachment/201205/30/26833883_13383682995iuI.png)
其原型:
![](/attachment/201205/30/26833883_1338368334x8n8.png)
![](/attachment/201205/30/26833883_13383681747UiI.png)
參数说明:
第一个參数:指定发送信号的接收线程
第二个參数:信号的signum
案例一、
父进程从终端输入signum,然后发给子进程
点击(此处)折叠或打开
- #include <stdio.h>
- #include <sys/types.h>
- #include <signal.h>
- #include <stdlib.h>
- int main()
- {
- int pid;
- if((pid = fork()) < 0)
- {
-
- perror("Fail to fork");
- exit(EXIT_FAILURE);
-
- }else if(pid == 0){
-
- while(1);
-
- }else{
-
- int signum;
-
- while(scanf("%d",&signum) == 1)
- {
- kill(pid,signum);
- system("ps -aux | grep a.out");
- }
- }
- return 0;
- }
运行结果例如以下:
![](/attachment/201205/30/26833883_1338368246TAub.png)
B.捕捉一个信号
![](/attachment/201205/30/26833883_1338368273dQ8B.png)
相应的API
![](/attachment/201205/30/26833883_13383682995iuI.png)
其原型:
![](/attachment/201205/30/26833883_1338368334x8n8.png)
我们一般都是用第一个,也就是通过typedef改写过的。
注意:signal函数我一般觉得其是向内核注冊当前进程收到信号的处理的方式。
signal(SIGINT,handler);
參数说明:
signum : 指定信号
handler : SIG_IGN忽略该信号,SIG_DFL採用系统默认方式处理信号,自己定义的信号处理函数指针。
案例探究:
通过异步方式,给子进程收尸
注意:子进程在终止时会给父进程发SIGCHLD,该信号的默认处理动作是忽略。父进程能够自己定义SIGCHLD信号的处理函数,这样父进程仅仅须要专心处理自己的工作。不必关心子进程了。子进程终止时会通知父进程。父进程在信号处理函数中调用wait清理子进程就可以。
点击(此处)折叠或打开
- #include <stdio.h>
- #include <signal.h>
- #include <unistd.h>
- #include <stdlib.h>
- void child_exit_handler(int signum)
- {
- if(signum == SIGCHLD)
- {
- printf("Child exit.\n");
- wait(NULL);
- }
- }
- int main()
- {
- int pid;
- int i = 0;
- //想内核注冊,处理 SIGCHLD信号的方式
- signal(SIGCHLD,child_exit_handler);
- if((pid = fork()) < 0)
- {
- perror("Fail to fork");
- exit(EXIT_FAILURE);
- }else if(pid == 0){
-
- for(i = 0;i < 5;i ++)
- {
- printf("child loop.\n");
- sleep(1);
- }
-
- }else{
-
- for(i = 0;i < 5;i ++)
- {
- printf("Father loop.\n");
- sleep(2);
- }
- }
- exit(EXIT_SUCCESS);
- }
C.闹钟函数alarm
![](/attachment/201205/30/26833883_1338368388F4VC.png)
larm()也称为闹钟函数,它能够在进程中设置一个定时器。当定时器指定的时间到时。内核就向进程发送SIGALARM信号。
seconds:指定的秒数,假设參数seconds为0。则之前设置的闹钟会被取消。并将剩下的时间返回。
成功:假设调用此alarm()前,进程中已经设置了闹钟时间,则放回上一个闹钟时间的剩余时间,否则返回0。
alarm(100);
........
......
alarm(5);
出错:-1
案例探究:
运行结果例如以下:
点击(此处)折叠或打开
- #include <stdio.h>
- #include <signal.h>
- #include <stdlib.h>
- void handler(int signum)
- {
- if(signum == SIGALRM)
- {
- printf("Recv SIGALARM.\n");
- }
- exit(EXIT_SUCCESS);
- }
- int main()
- {
- int count = 0;
- int n = 0;
- signal(SIGALRM,handler);
- n = alarm(10);
- printf("n = %d.\n",n);
-
- sleep(2);
- n = alarm(5);
- printf("n = %d.\n",n);
-
- while(1)
- {
- printf("count = %d.\n", ++count);
- sleep(1);
- }
- return 0;
- }
![](/attachment/201205/30/26833883_1338368443Z90f.png)
案例二、综合案例
使用FIFO实现clientA与clientB之间聊天
A.输入quit后,两个进程退出
B.假设在20秒内。没有等到还有一端发来的消息,则觉得对方已不在。此时终止。
clientA:
client B
D.将进程挂起函数pause
![](/attachment/201205/30/26833883_1338368523ssSV.png)
![](/attachment/201205/30/26833883_1338368548ee3E.png)
案比例如以下:
![](/attachment/201205/30/26833883_13383685789XzG.png)
点击(此处)折叠或打开
- #include <stdio.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <string.h>
- #include <fcntl.h>
- #define MAX 100
- void signal_handler(int signum)
- {
- static int flag = 0;
- switch(signum)
- {
- case SIGALRM:
- if(flag == 0)
- {
- printf("The people is leaving,the system is closed in 10 seconds \
- and you can input 'ctrl + c' cancel.\n");
- alarm(10);
- }else{
-
- kill(getppid(),SIGKILL);
- usleep(500);
- exit(EXIT_SUCCESS);
- }
- flag = 1;
- break;
- case SIGINT:
- printf("The alarm is cancel.\n");
- alarm(0);
- break;
- }
- }
- int child_recv_fifo(char *fifo_name)
- {
- int n,fd;
- char buf[MAX];
- if((fd = open(fifo_name,O_RDONLY)) < 0)
- {
- fprintf(stderr,"fail to open %s : %s.\n",fifo_name,strerror(errno));
- return -1;
- }
- signal(SIGALRM,signal_handler);
- signal(SIGINT,signal_handler);
- alarm(15);//璁剧疆瀹氭椂鍣?
- while(1)
- {
- n = read(fd,buf,sizeof(buf));
- buf[n] = '\0';
- printf("Read %d bytes : %s.\n",n,buf);
- if(strncmp(buf,"quit",4) == 0 || n == 0)
- {
- kill(getppid(),SIGKILL);
- usleep(500);
- exit(EXIT_SUCCESS);
- }
- alarm(15);
- }
- return 0;
- }
- int father_send_fifo(char *fifo_name,int pid)
- {
- int n,fd;
- char buf[MAX];
- if((fd = open(fifo_name,O_WRONLY)) < 0)
- {
- fprintf(stderr,"Fail to open %s : %s.\n",fifo_name,strerror(errno));
- return -1;
- }
- signal(SIGINT,SIG_IGN);
- while(1)
- {
- getchar();
- printf(">");
- fgets(buf,sizeof(buf),stdin);
- buf[strlen(buf)-1] = '\0';
- write(fd,buf,strlen(buf));
- if(strncmp(buf,"quit",4) == 0)
- {
- kill(pid,SIGKILL);
- usleep(500);
- exit(EXIT_SUCCESS);
- }
- }
- return 0;
- }
- int main(int argc,char *argv[])
- {
- int pid;
- if(argc < 3)
- {
- fprintf(stderr,"usage %s argv[1].\n",argv[0]);
- exit(EXIT_FAILURE);
- }
- if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)
- {
- perror("Fail to mkfifo");
- exit(EXIT_FAILURE);
- }
- if(mkfifo(argv[2],0666) < 0 && errno != EEXIST)
- {
- perror("Fail to mkfifo");
- exit(EXIT_FAILURE);
- }
-
- if((pid = fork()) < 0)
- {
-
- perror("Fail to fork");
- exit(EXIT_FAILURE);
-
- }else if(pid == 0){
-
- child_recv_fifo(argv[2]);
-
- }else{
- father_send_fifo(argv[1],pid);
- }
- exit(EXIT_SUCCESS);
- }
client B
点击(此处)折叠或打开
- #include <stdio.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <string.h>
- #include <fcntl.h>
- #define MAX 100
- void signal_handler(int signum)
- {
- static int flag = 0;
- switch(signum)
- {
- case SIGALRM:
- if(flag == 0)
- {
- printf("The people is leaving,the system is closed in 10 seconds \
- and you can input 'ctrl + c' cancel.\n");
- alarm(10);
- }else{
-
- kill(getppid(),SIGKILL);
- usleep(500);
- exit(EXIT_SUCCESS);
- }
- flag = 1;
- break;
- case SIGINT:
- printf("The alarm is cancel.\n");
- alarm(0);
- break;
- }
- }
- int child_recv_fifo(char *fifo_name)
- {
- int n,fd;
- char buf[MAX];
- if((fd = open(fifo_name,O_RDONLY)) < 0)
- {
- fprintf(stderr,"fail to open %s : %s.\n",fifo_name,strerror(errno));
- return -1;
- }
- signal(SIGALRM,signal_handler);
- signal(SIGINT,signal_handler);
- alarm(15);//璁剧疆瀹氭椂鍣?
- while(1)
- {
- n = read(fd,buf,sizeof(buf));
- buf[n] = '\0';
- printf("Read %d bytes : %s.\n",n,buf);
- if(strncmp(buf,"quit",4) == 0 || n == 0)
- {
- kill(getppid(),SIGKILL);
- usleep(500);
- exit(EXIT_SUCCESS);
- }
- alarm(15);
- }
- return 0;
- }
- int father_send_fifo(char *fifo_name,int pid)
- {
- int n,fd;
- char buf[MAX];
- if((fd = open(fifo_name,O_WRONLY)) < 0)
- {
- fprintf(stderr,"Fail to open %s : %s.\n",fifo_name,strerror(errno));
- return -1;
- }
- signal(SIGINT,SIG_IGN);
- while(1)
- {
- getchar();
- printf(">");
- fgets(buf,sizeof(buf),stdin);
- buf[strlen(buf)-1] = '\0';
- write(fd,buf,strlen(buf));
- if(strncmp(buf,"quit",4) == 0)
- {
- kill(pid,SIGKILL);
- usleep(500);
- exit(EXIT_SUCCESS);
- }
- }
- return 0;
- }
- int main(int argc,char *argv[])
- {
- int pid;
- if(argc < 3)
- {
- fprintf(stderr,"usage %s argv[1].\n",argv[0]);
- exit(EXIT_FAILURE);
- }
- if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)
- {
- perror("Fail to mkfifo");
- exit(EXIT_FAILURE);
- }
- if(mkfifo(argv[2],0666) < 0 && errno != EEXIST)
- {
- perror("Fail to mkfifo");
- exit(EXIT_FAILURE);
- }
-
- if((pid = fork()) < 0)
- {
-
- perror("Fail to fork");
- exit(EXIT_FAILURE);
-
- }else if(pid == 0){
-
- child_recv_fifo(argv[1]);
-
- }else{
- father_send_fifo(argv[2],pid);
- }
- exit(EXIT_SUCCESS);
- }
D.将进程挂起函数pause
![](/attachment/201205/30/26833883_1338368523ssSV.png)
解释例如以下:
![](/attachment/201205/30/26833883_1338368548ee3E.png)
案比例如以下:
![](/attachment/201205/30/26833883_13383685789XzG.png)
相关热门文章
给主人留下些什么吧!~~
评论热议