linux 進程之間通訊 整理

來源:互聯網
上載者:User
# 管道( pipe ):  管道是一種半雙工的通訊方式,資料只能單向流動,而且只能在具有親緣關係的進程間使用。進程的親緣關係通常是指父子進程關係。# 有名管道 (named pipe) :   有名管道也是半雙工的通訊方式,但是它允許無親緣關係進程間的通訊。# 訊號量( semophore ) :   訊號量是一個計數器,可以用來控制多個進程對共用資源的訪問。它常作為一種鎖機制,防止某進程正在訪問共用資源時,其他進程也訪問該資源。因此,主要作為進程間以及同一進程內不同線程之間的同步手段。# 訊息佇列( message queue ) :   訊息佇列是由訊息的鏈表,存放在核心中並由訊息佇列標識符標識。訊息佇列克服了訊號傳遞資訊少、管道只能承載無格式位元組流以及緩衝區大小受限等缺點。# 訊號 ( sinal ) :   訊號是一種比較複雜的通訊方式,用於通知接收進程某個事件已經發生。# 共用記憶體( shared memory ) :  共用記憶體就是映射一段能被其他進程所訪問的記憶體,這段共用記憶體由一個進程建立,但多個進程都可以訪問。共用記憶體是最快的 IPC 方式,它是針對其他處理序間通訊方式運行效率低而專門設計的。它往往與其他通訊機制,如訊號兩,配合使用,來實現進程間的同步和通訊。# 通訊端( socket ) :   套解口也是一種處理序間通訊機制,與其他通訊機制不同的是,它可用於不同及其間的進程通訊。

 

一、處理序間通訊概述
進程通訊有如下一些目的:
A、資料轉送:一個進程需要將它的資料發送給另一個進程,發送的資料量在一個位元組到幾M位元組之間
B、共用資料:多個進程想要操作共用資料,一個進程對共用資料的修改,別的進程應該立刻看到。
C、通知事件:一個進程需要向另一個或一組進程發送訊息,通知它(它們)發生了某種事件(如進程終止時要通知父進程)。
D、資源共用:多個進程之間共用同樣的資源。為了作到這一點,需要核心提供鎖和同步機制。
E、進程式控制制:有些進程希望完全控制另一個進程的執行(如Debug進程),此時控制進程希望能夠攔截另一個進程的所有陷入和異常,並能夠及時知道它的狀態改變。
Linux 處理序間通訊(IPC)以下以幾部分發展而來:
早期UNIX處理序間通訊、基於System V處理序間通訊、基於Socket處理序間通訊和POSIX處理序間通訊。
UNIX處理序間通訊方式包括:管道、FIFO、訊號。
System V處理序間通訊方式包括:System V訊息佇列、System V號誌、System V共用記憶體、
POSIX處理序間通訊包括:posix訊息佇列、posix號誌、posix共用記憶體。
現在linux使用的處理序間通訊方式:
(1)管道(pipe)和有名管道(FIFO)
(2)訊號(signal)
(3)訊息佇列
(4)共用記憶體
(5)訊號量
(6)通訊端(socket)二、管道通訊普通的Linux shell都允許重新導向,而重新導向使用的就是管道。例如:
ps | grep vsftpd .管道是單向的、先進先出的、無結構的、固定大小的位元組流,它把一個進程的標準輸出和另一個進程的標準輸入串連在一起。寫進程在管道的尾端寫入資料,讀進程在管道的道端讀出資料。資料讀出後將從管道中移走,其它讀進程都不能再讀到這些資料。管道提供了簡單的流量控制機制。進程試圖讀空管道時,在有資料寫入管道前,進程將一直阻塞。同樣,管道已經滿時,進程再試圖寫管道,在其它進程從管道中移走資料之前,寫進程將一直阻塞。管道主要用於不同處理序間通訊。管道建立與關閉
建立一個簡單的管道,可以使用系統調用pipe()。它接受一個參數,也就是一個包括兩個整數的數組。如果系統調用成功,此數組將包括管道使用的兩個檔案描述符。建立一個管道之後,一般情況下進程將產生一個新的進程。
系統調用:pipe();
原型:int pipe(int fd[2]);
傳回值:如果系統調用成功,返回0。如果系統調用失敗返回-1:
errno=EMFILE(沒有空親的檔案描述符)
      EMFILE(系統檔案表已滿)
      EFAULT(fd數組無效)
注意:fd[0]用於讀取管道,fd[1]用於寫入管道。
圖見附件
管道的建立
#include<unistd.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>int main()
{
int pipe_fd[2];
if(pipe(pipe_fd)<0){
printf("pipe create error\n");
return -1;
}
else
printf("pipe create success\n");
close(pipe_fd[0]);
close(pipe_fd[1]);
}管道的讀寫
管道主要用於不同處理序間通訊。實際上,通常先建立一個管道,再通過fork函數建立一個子進程。圖見附件。子進程寫入和父進程讀的具名管道:圖見附件管道讀寫注意事項:
可以通過開啟兩個管道來建立一個雙向的管道。但需要在子理程中正確地設定檔案描述符。必須在系統調用fork()中調用pipe(),否則子進程將不會繼承檔案描述符。當使用半雙工管道時,任何關聯的進程都必須共用一個相關的祖先進程。因為管道存在於系統核心之中,所以任何不在建立管道的進程的祖先進程之中的進程都將無法定址它。而在具名管道中卻不是這樣。管道執行個體見:pipe_rw.c#include<unistd.h>
#include<memory.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>int main()
{
int pipe_fd[2];
pid_t pid;
char buf_r[100];
char* p_wbuf;
int r_num;memset(buf_r,0,sizeof(buf_r));數組中的資料清0;if(pipe(pipe_fd)<0){
printf("pipe create error\n");
return -1;
}if((pid=fork())==0){
printf("\n");
close(pipe_fd[1]);
sleep(2);
if((r_num=read(pipe_fd[0],buf_r,100))>0){
printf("%d numbers read from be pipe is %s\n",r_num,buf_r);
}
close(pipe_fd[0]);
exit(0);
}else if(pid>0){
close(pipe_fd[0]);
if(write(pipe_fd[1],"Hello",5)!=-1)
printf("parent write success!\n");
if(write(pipe_fd[1]," Pipe",5)!=-1)
printf("parent wirte2 succes!\n");
close(pipe_fd[1]);
sleep(3);
waitpid(pid,NULL,0);
exit(0);
}
}標準流管道
與linux中檔案操作有檔案流的標準I/O一樣,管道的操作也支援基於檔案流的模式。介面函數如下:
庫函數:popen();
原型:FILE *open (char *command,char *type);
傳回值:如果成功,返回一個新的檔案流。如果無法建立進程或者管道,返回NULL。管道中資料流的方向是由第二個參數type控制的。此參數可以是r或者w,分別代表讀或寫。但不能同時為讀和寫。在Linux 系統下,管道將會以參數type中第一個字元代表的方式開啟。所以,如果你在參數type中寫入rw,管道將會以讀的方式開啟。使用popen()建立的管道必須使用pclose()關閉。其實,popen/pclose和標準檔案輸入/輸出流中的fopen()/fclose()十分相似。
庫函數:pclose();
原型:int pclose(FILE *stream);
傳回值:返回系統調用wait4()的狀態。
如果stream無效,或者系統調用wait4()失敗,則返回-1。注意此庫函數等待管道進程運行結束,然後關閉檔案流。庫函數pclose()在使用popen()建立的進程上執行wait4()函數,它將破壞管道和檔案系統。
流管道的例子。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#define BUFSIZE 1024
int main(){
FILE *fp;
char *cmd="ps -ef";
char buf[BUFSIZE];
buf[BUFSIZE]='\0';
if((fp=popen(cmd,"r"))==NULL)
 perror("popen");
while((fgets(buf,BUFSIZE,fp))!=NULL)
 printf("%s",buf);
pclose(fp);
exit(0);
}具名管道(FIFO)
基本概念
具名管道和一般的管道基本相同,但也有一些顯著的不同:
A、具名管道是在檔案系統中作為一個特殊的裝置檔案而存在的。
B、不同祖先的進程之間可以通過管道共用資料。
C、當共用管道的進程執行完所有的I/O操作以後,具名管道將繼續儲存在檔案系統中以便以後使用。
管道只能由相關進程使用,它們共同的祖先進程建立了管道。但是,通過FIFO,不相關的進程也能交換資料。具名管道建立與操作
具名管道建立
#include<sys/types.h>
#include<sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);
返回:若成功則為0,若出錯返回-1
一旦已經用mkfifo建立了一個FIFO,就可用open開啟它。確實,一般的檔案I/O函數(close,read,write,unlink等)都可用於FIFO。當開啟一個FIFO時,非阻塞標(O_NONBLOCK)產生下列影響:
(1)在一般情況中(沒有說明O_NONBLOCK),唯讀開啟要阻塞到某個其他進程為寫開啟此FIFO。類似,為寫而開啟一個FIFO要阻塞到某個其他進程為讀而開啟它。
(2)如果指一了O_NONBLOCK,則唯讀開啟立即返回。但是,如果沒有進程已經為讀而開啟一個FIFO,那麼唯寫開啟將出錯返回,其errno是ENXIO。類似於管道,若寫一個尚無進程為讀而開啟的FIFO,則產生訊號SIGPIPE。若某個FIFO的最後一個寫進程關閉了該FIFO,則將為該FIFO的讀進程產生一個檔案結束標誌。
FIFO相關出錯資訊:
EACCES(無存取許可權)
EEXIST(指定檔案不存在)
ENAMETOOLONG(路徑名太長)
ENOENT(包含的目錄不存在)
ENOSPC(檔案系統餘空間不足)
ENOTDIR(檔案路徑無效)
EROFS(指定的檔案存在於唯讀檔案系統中)fifo_write.c 
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define FIFO "/tmp/myfifo"main(int argc,char** argv)
{
char buf_r[100];
int fd;
int nread;
if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))
printf("cannot create fifoserver\n");
printf("Preparing for reading bytes....\n");
memset(buf_r,0,sizeof(buf_r));
fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);
if(fd==-1)
{
perror("open");
exit(1);
}
while(1){
memset(buf_r,0,sizeof(buf_r));
if((nread=read(fd,buf_r,100))==-1){
if(errno==EAGAIN)
printf("no data yet\n");
}
printf("read %s from FIFO\n",buf_r);
sleep(1);
}
pause();
unlink(FIFO);
}fifo_read.c
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define FIFO_SERVER "/tmp/myfifo"
main(int argc,char** argv)
{
int fd;
char w_buf[100];
int nwrite;
if(fd==-1)
if(errno==ENXIO)
printf("open error;no reading process\n");
fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);
if(argc==1)
printf("Please send something\n");
strcpy(w_buf,argv[1]);
if((nwrite=write(fd,w_buf,100))==-1)
{
if(errno==EAGAIN)
printf("The FIFO has not been read yet. Please try later\n");
}
else 
printf("write %s to the FIFO\n",w_buf);
}三、訊號
訊號概述
訊號是軟體中斷。訊號(signal)機制是Unix系統中最為古老的進程之間的能信機制。它用於在一個或多個進程之間傳遞非同步訊號。很多條件可以產生一個訊號。
A、當使用者按某些終端鍵時,產生訊號。在終端上按DELETE鍵通常產生中斷訊號(SIGINT)。這是停止一個已失去控製程序的方法。
B、硬體異常產生訊號:除數為0、無效的儲存訪問等等。這些條件通常由硬體檢測到,並將其通知核心。然後核心為該條件發生時正在啟動並執行進程產生適當的訊號。例如,對於執行一個無效儲存訪問的進程產生一個SIGSEGV。
C、進程用kill(2)函數可將訊號發送給另一個進程或進程組。自然,有些限制:接收訊號進和發送訊號進程的所有都必須相同,或發送訊號進程的的所有者必須是超級使用者。
D、使用者可用Kill(ID 值)命令將訊號發送給其它進程。此程式是Kill函數的介面。常用此命令終止一個失控的後台進程。
E、當檢測到某種軟體條件已經發生,並將其通知有關進程時也產生訊號。這裡並不是指硬體產生條件(如被0除),而是軟體條件。例如SIGURG(在網路連接上傳來非規定傳輸速率的資料)、SIGPIPE(在管道的讀進程已終止後一個進程寫此管道),以及SIGALRM(進程所設定的鬧鐘時間已經逾時)。核心為進程生產訊號,來響應不同的事件,這些事件就是訊號源。主要訊號源如下:
(1)異常:進程運行過程中出現異常;
(2)其它進程:一個進程可以向另一個或一組進程發送訊號;
(3)終端中斷:Ctrl-c,Ctro-\等;
(4)作業控制:前台、後台進程的管理;
(5)分配額:CPU逾時或檔案大小突破限制;
(6)通知:通知進程某事件發生,如I/O就緒等;
(7)警示:計時器到期;Linux中的訊號
1、SIGHUP 2、SIGINT(終止) 3、SIGQUIT(退出) 4、SIGILL 5、SIGTRAP 6、SIGIOT  7、SIGBUS   8、SIGFPE   9、SIGKILL 10、SIGUSER 11、 SIGSEGV SIGUSER 12、 SIGPIPE 13、SIGALRM 14、SIGTERM 15、SIGCHLD 16、SIGCONT 17、SIGSTOP 18、SIGTSTP 19、SIGTTIN 20、SIGTTOU 21、SIGURG 22、SIGXCPU 23、SIGXFSZ
24、SIGVTALRM 25、SIGPROF 26、SIGWINCH 27、SIGIO 28、SIGPWR常用的訊號:
SIGHUP:從終端上發出的結束訊號;
SIGINT:來自鍵盤的中斷訊號(Ctrl+c)
SIGQUIT:來自鍵盤的退出訊號;
SIGFPE:浮點異常訊號(例如浮點運算溢出);
SIGKILL:該訊號結束接收訊號的進程;
SIGALRM:進程的定時器到期時,發送該訊號;
SIGTERM:kill命令生出的訊號;
SIGCHLD:標識子進程停止或結束的訊號;
SIGSTOP:來自鍵盤(Ctrl-Z)或偵錯工具的停止掃行訊號可以要求系統在某個訊號出現時按照下列三種方式中的一種進行操作。
(1)忽略此訊號。大多數訊號都可使用這種方式進行處理,但有兩種訊號卻決不能被忽略。它們是:SIGKILL和SIGSTOP。這兩種訊號不能被忽略的,原因是:它們向超級使用者提供一種使進程終止或停止的可靠方法。另外,如果忽略某些由硬體異常產生的訊號(例如非法儲存訪問或除以0),則進程的行為是示定義的。
(2)捕捉訊號。為了做到這一點要通知核心在某種訊號發生時,調用一個使用者函數。在使用者函數中,可執行使用者希望對這種事件進行的處理。如果捕捉到SIGCHLD訊號,則表示子進程已經終止,所以此訊號的捕捉函數可以調用waitpid以取得該子進程的進程ID以及它的終止狀態。
(3)執行系統預設動作。對大多數訊號的系統預設動作是終止該進程。每一個訊號都有一個預設動作,它是當進程沒有給這個訊號指定處理常式時,核心對訊號的處理。有5種預設的動作:
(1)異常終止(abort):在進程的目前的目錄下,把進程的地址空間內容、寄存器內容儲存到一個叫做core的檔案中,而後終止進程。
(2)退出(exit):不產生core檔案,直接終止進程。
(3)忽略(ignore):忽略該訊號。
(4)停止(stop):掛起該進程。
(5)繼續(contiune):如果進程被掛起,剛恢複進程的動行。否則,忽略訊號。訊號的發送與捕捉
kill()和raise()
kill()不僅可以中止進程,也可以向進程發送其他訊號。
與kill函數不同的是,raise()函數運行向進程自身發送訊號
#include<sys/types.h>
#include<signal.h>
int kill(pid_t pid,int signo);
int raise(int signo);
兩個函數返回:若成功則為0,若出錯則為-1。
kill的pid參數有四種不同的情況:
(1)pid>0將訊號發送給進程ID為pid的進程。
(2)pid==0將訊號發送給其進程組ID等於發送進程的進程組ID,而且發送進程有許可權向其發送訊號的所有進程。
(3)pid<0將訊號發送給其進程組ID等於pid絕對值,而且發送進程有許可權向其發送訊號的所有進程。如上所述一樣,“所有進程”並不包括系統進程集中的進程。
(4)pid==-1 POSIX.1未定義種情況
kill.c 
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
pid_t pid;
int ret;
if((pid==fork())<0){
perro("fork");
exit(1);
}
if(pid==0){
raise(SIGSTOP);
exit(0);
}else {
printf("pid=%d\n",pid);
if((waitpid(pid,NULL,WNOHANG))==0){
if((ret=kill(pid,SIGKILL))==0)
printf("kill %d\n",pid);
else{
perror("kill");
}
}
}
}alarm和pause函數
使用alarm函數可以設定一個時間值(鬧鐘時間),在將來的某個時刻時間值會被超過。當所設定的時間被超過後,產生SIGALRM訊號。如果不忽略或不捕捉引訊號,則其預設動作是終止該進程。
#include<unistd.h>
unsigned int alarm(unsigned int secondss);
返回:0或以前設定的鬧鐘時間的餘留秒數。參數seconds的值是秒數,經過了指定的seconds秒後產生訊號SIGALRM。每個進程只能有一個鬧鐘時間。如果在調用alarm時,以前已為該進程設定過鬧鐘時間,而且它還沒有逾時,則該鬧鐘時間的餘留值作為本次alarm函數調用的值返回。以前登記的鬧鐘時間則被新值代換。
如果有以前登記的尚未超過的鬧鐘時間,而且seconds值是0,則取消以前的鬧鐘時間,其餘留值仍作為函數的傳回值。pause函數使用調用進程掛起直至捕捉到一個訊號
#include<unistd.h>
int pause(void);
返回:-1,errno設定為EINTR
只有執行了一訊號處理常式並從其返回時,pause才返回。alarm.c
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
int ret;
ret=alarm(5);
pause();
printf("I have been waken up.\n",ret);
}訊號的處理
當系統捕捉到某個訊號時,可以忽略誰訊號或是使用指定的處理函數來處理該訊號,或者使用系統預設的方式。訊號處理的主要方式有兩種,一種是使用簡單的signal函數,別一種是使用訊號集合函式組。
signal()
#include<signal.h>
void (*signal (int signo,void (*func)(int)))(int)
返回:成功則為以前的訊號處理配置,若出錯則為SIG_ERR
func的值是:(a)常數SIGIGN,或(b)常數SIGDFL,或(c)當接到此訊號後要調用的的函數的地址。如果指定SIGIGN,則向核心表示忽略此訊號(有兩個訊號SIGKILL和SIGSTOP不能忽略)。如果指定SIGDFL,則表示接到此訊號後的動作是系統預設動作。當指定函數地址時,我們稱此為捕捉此訊號。我們稱此函數為訊號處理常式(signal handler)或訊號捕捉函數(signal-catching funcgion).signal函數原型太複雜了,如果使用下面的typedef,則可以使其簡化。
type void sign(int);
sign *signal(int,handler *);
執行個體見:mysignal.c
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
void my_func(int sign_no)
{
if(sign_no==SIGINT)
 printf("I have get SIGINT\n");
else if(sign_no==SIGQUIT)
 printf("I have get SIGQUIT\n");
}
int main()
{
 printf("Waiting for signal SIGINT or SIGQUTI\n");
 signal(SIGINT,my_func);
 signal(SIGQUIT,my_func);
 pasue();
 exit(0);
}
訊號集合函式組
我們需要有一個能表示多個訊號——訊號集(signal set)的資料類型。將在sigprocmask()這樣的函數中使用這種資料類型,以告訴核心不允許發生該訊號集中的訊號。訊號集合函式組包含水量幾大模組:建立函數集、登記訊號集、活動訊號集。
圖見附件。建立函數集
#include<signal.h>
int sigemptyset(sigset_t* set);
int sigfillset(sigset_t* set);
int sigaddset(sigset_t* set,int signo );
int sigdelset(sigset_t* set,int signo);
四個函數返回:若成功則為0,若出錯則為-1
int sigismember(const sigset_t* set,int signo);
返回:若真則為1,若假則為0;
signemptyset:初始化訊號集合為空白。
sigfillset:初始化訊號集合為所有的訊號集合。
sigaddset:將指定訊號添加到現存集中。
sigdelset:從訊號集中刪除指定訊號。
sigismember:查詢指定訊號是否在訊號集中。登記訊號集
登記訊號處理機主要用於決定進程如何處理訊號。首先要判斷出當前進程阻塞能不能傳遞給該訊號的訊號集。這首先使用sigprocmask函數判斷檢測或更改訊號屏蔽字,然後使用sigaction函數改變進程接受到特定訊號之後的行為。
一個進程的訊號屏蔽字可以規定當前阻塞而不能遞送給該進程的訊號集。調用函數sigprocmask可以檢測或更改(或兩者)進程的訊號屏蔽字。
#include<signal.h>
int sigprocmask(int how,const sigset_t* set,sigset_t* oset);
返回:若成功則為0,若出錯則為-1
oset是非null 指標,進程是當前訊號屏蔽字通過oset返回。其次,若set是一個非null 指標,則參數how指示如何修改當前訊號屏蔽字。
用sigprocmask更改當前訊號屏蔽字的方法。how參數設定:
SIG_BLOCK該進程新的訊號屏蔽字是其當前訊號屏蔽字和set指向訊號集的並集。set包含了我們希望阻塞的附加訊號。
SIG_NUBLOCK該進程新的訊號屏蔽字是其當前訊號屏蔽字和set所指向訊號集的交集。set包含了我們希望解除阻塞的訊號。
SIG_SETMASK該進程新的訊號屏蔽是set指向的值。如果set是個null 指標,則不改變該進程的訊號屏蔽字,how的值也無意義。
sigaction函數的功能是檢查或修改(或兩者)與指定訊號相關聯的處理動作。此函數取代了UNIX早期版本使用的signal函數。
#include<signal.h>
int sigaction(int signo,const struct sigaction* act,struct sigaction* oact);
返回:若成功則為0,若出錯則為-1
參數signo是要檢測或修改具體動作的訊號的編號數。若act指標非空,則要修改其動作。如果oact指標為空白,則系統返回該訊號的原先動作。此函數使用下列結構:
struct sigaction{
void (*sa_handler)(int signo);
sigset_t sa_mask;
int sa_flags;
void (*sa_restore);
};
sa_handler是一個函數指標,指定訊號關聯函數,可以是自訂處理函數,還可以SIG_DEF或SIG_IGN;
sa_mask是一個訊號集,它可以指定在訊號處理常式執行過程中哪些訊號應當被阻塞。
sa_flags中包含許多標誌位,是對訊號進行處理的各種選項。具體如下:
SA_NODEFER\SA_NOMASK:當捕捉到此訊號時,在執行其訊號捕捉函數時,系統不會自動阻塞此訊號。
SA_NOCLDSTOP:進程忽略子進程產生的任何SIGSTOP、SIGTSTP、SIGTTIN和SIGTOU訊號
SA_RESTART:可讓重啟的系統調用重新起作用。
SA_ONESHOT\SA_RESETHAND:自訂訊號只執行一次,在執行完畢後恢複訊號的系統預設動作。
活動訊號是訊號處理的後續步驟,但不是必須的。sigpending函數運行進程檢測“未決“訊號(進程不清楚他的存在),並進一步決定對他們做何處理。
sigpending返回對於調用進程被阻塞不能遞送和當前未決的訊號集。
#include<signal.h>
int sigpending(sigset_t * set);
返回:若成功則為0,若出錯則為-1
訊號集執行個體見:sigaction.c
#include<sys/types.h>
#include<unistd.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
void my_func(int signum){
printf("If you want to quit,please try SIGQUIT\n");
}
int main()
{
sigset_t set,pendset;
struct sigaction action1,action2;
if(sigemptyse(&set)<0)
perror("sigemptyset");
if(sigaddset(&set,SIGQUIT)<0)
perror("sigaddset");
if(sigaddset(&set,SIGINT)<0)
perror("sigaddset");
if(sigprocmask(SIG_BLOCK,&set,NULL)<0)
perror("sigprcmask");
esle{
printf("blocked\n");
sleep(5);
}
if(sigprocmask(SIG_UNBLOCK,&set,NULL)
perror("sigprocmask");
else
printf("unblock\n");
while(1){
if(sigismember(&set,SIGINT)){
sigemptyset(&action1.sa_mask);
action1.sa_handler=my_func;
sigaction(SIGINT,&action1,NULL);
}else if(sigismember(&set,SIGQUIT)){
sigemptyset(&action2.sa_mask);
action2.sa_handler=SIG_DEL;
sigaction(SIGTERM,&action2,NULL);
}
}
}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.