進程間通訊--信號(進程間通訊惟一的異步方式

進程間通訊--信號(進程間通訊惟一的異步方式)   css

原文地址:進程間通訊--信號(進程間通訊惟一的異步方式) 做者:Deem_passionhtml


1、信號的介紹 linux


信號是在軟件層次上對中斷機制的一種模擬,是一種異步通訊方式。異步


信號能夠直接進行用戶空間進程和內核進程之間的交互,內核進程也能夠利用它來通知用戶空間進程發生了那些系統事件。ide


若是該進程當前並未處於執行態,則該信號就由內核保存起來,直到該進程恢復執行再傳遞個它;若是一個信號被進程設置爲阻塞,則該信號的傳遞被延遲,直到其阻塞取消時才被傳遞給進程。函數


2、linux操做系統支持的信號oop


A. kill  -l

26833883_1338368070RJZ9.png

B.經常使用信號的含義

26833883_1338368118pO0w.png

26833883_1338368141wW9t.png

ui

3、信號的產生spa


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信號。


4、進程對信號的處理


A.忽略此信號

B.執行該信號的默認處理動做

C.提供一個信號處理函數,要求內核在處理該信號時切換到用戶態執行這個處理函數,這種方式成爲捕捉(Catch)一個信號。

 


5、相關信號API


A.經過系統調用向一個指定的進程發送信號

26833883_13383681747UiI.png

參數說明:

第一個參數:指定發送信號的接收線程

第二個參數:信號的signum


案例1、

父進程從終端輸入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. }


運行結果以下:

26833883_1338368246TAub.png

B.捕捉一個信號

26833883_1338368273dQ8B.png

對應的API

26833883_13383682995iuI.png

其原型:

26833883_1338368334x8n8.png


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


26833883_1338368388F4VC.png

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

運行結果以下:


26833883_1338368443Z90f.png

案例2、綜合案例


使用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

26833883_1338368523ssSV.png

解釋以下:


26833883_1338368548ee3E.png

案例以下:

26833883_13383685789XzG.png

相關文章
相關標籤/搜索