一、信號的介紹
信號是在軟件層次上對中斷機制的一種模擬,是一種異步通信方式。
信號能夠直接進行用戶空間進程和內核進程之間的交互,內核進程也能夠利用它來通知用戶空間進程發生了那些系統事件。
假設該進程當前並未處於運行態,則該信號就由內核保存起來,直到該進程恢復運行再傳遞個它;假設一個信號被進程設置為堵塞。則該信號的傳遞被延遲,直到其堵塞取消時才被傳遞給進程。
二、linux操作系統支持的信號
A. kill -l
B.經常使用信號的含義

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.通過系統調用向一個指定的進程發送信號
運行結果例如以下:
B.捕捉一個信號
相應的API
其原型:

參數說明:
第一個參數:指定發送信號的接收線程
第二個參數:信號的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;
- }
運行結果例如以下:

B.捕捉一個信號

相應的API

其原型:

我們一般都是用第一個,也就是通過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

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;
- }

案例二、綜合案例
使用FIFO實現clientA與clientB之間聊天
A.輸入quit后,兩個進程退出
B.假設在20秒內。沒有等到還有一端發來的消息,則覺得對方已不在。此時終止。
clientA:
client B
D.將進程掛起函數pause
案比例如以下:
點擊(此處)折疊或打開
- #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

解釋例如以下:

案比例如以下:
