[英]Trouble sending signal between parent and child process in C
我正在按照指導進行研究項目,但遇到了問題。 我必須使用信號和管道進行通信,如下所示:
不幸的是,當我發送一個受支持的信號(例如20個)以處理2個信號時,信號被循環並且SIGUSR1終止了程序。
int stopm=0;
int stop1=0;
int stop2=0;
int stop3=0;
int termm=1;
int term1=1;
int term2=1;
int term3=1;
void obslugam(int sig){
signal(15,obslugam);
signal(18,obslugam);
signal(20,obslugam);
sigset_t mask_set;
sigfillset(&mask_set);
sigdelset(&mask_set,SIGUSR1);
sigdelset(&mask_set,SIGTERM);
sigdelset(&mask_set,SIGCONT);
sigdelset(&mask_set,SIGTSTP);
sigprocmask(SIG_BLOCK,&mask_set,NULL);
printf("Jestem M i odebralem sygnal %d\n",sig);
if(sig==15){
write(pm1[1],"15",2);
write(pm2[1],"15",2);
write(pm3[1],"15",2);
}
if(sig==18){
write(pm1[1],"18",2);
write(pm2[1],"18",2);
write(pm3[1],"18",2);
}
if(sig==20){
write(pm1[1],"20",2);
write(pm2[1],"20",2);
write(pm3[1],"20",2);
}
kill(PID1,10);
}
void obsluga1(int sig){
signal(10,obsluga1);
sigset_t mask_set;
sigfillset(&mask_set);
sigdelset(&mask_set,SIGUSR1);
sigprocmask(SIG_BLOCK,&mask_set,NULL);
printf("Jestem 1 i odebralem sygnal %d\n",sig);
char bufor_p1[2]={0};
if(read(pm1[0],&bufor_p1,2)==-1)perror("PIPE1\n");
if(strchr(bufor_p1,53)!=NULL) printf("Jestem 1 i dostałem 15\n");
else if(strchr(bufor_p1,56)!=NULL) printf("Jestem 1 i dostałem 18\n");
else if(strchr(bufor_p1,48)!=NULL) printf("Jestem 1 i dostałem 20\n");
kill(PID2,10);
}
void obsluga2(int sig){
signal(10,obsluga2);
signal(15,obsluga2);
signal(18,obsluga2);
signal(20,obsluga2);
sigset_t mask_set;
sigfillset(&mask_set);
sigdelset(&mask_set,SIGUSR1);
sigdelset(&mask_set,SIGTERM);
sigdelset(&mask_set,SIGCONT);
sigdelset(&mask_set,SIGTSTP);
sigprocmask(SIG_BLOCK,&mask_set,NULL);
printf("Jestem 2 i odebralem sygnal %d\n",sig);
if(sig==10){
char bufor_p2[2]={0};
if(read(pm2[0],&bufor_p2,2)==-1)perror("PIPE2\n");
if(strchr(bufor_p2,53)!=NULL) printf("Jestem 2 i dostałem 15\n");
else if(strchr(bufor_p2,56)!=NULL) printf("Jestem 2 i dostałem 18\n");
else if(strchr(bufor_p2,48)!=NULL) printf("Jestem 2 i dostałem 20\n");
kill(PID3,10);
}
else if(sig==15) kill(getppid(),15);
else if(sig==18) kill(getppid(),18);
else if(sig==20) kill(getppid(),20);
}
void obsluga3(int sig){
signal(10,obsluga3);
sigset_t mask_set;
sigfillset(&mask_set);
sigdelset(&mask_set,SIGUSR1);
sigprocmask(SIG_BLOCK,&mask_set,NULL);
printf("Jestem 3 i odebralem sygnal %d\n",sig);
char bufor_p3[2]={0};
if(read(pm3[0],&bufor_p3,2)==-1)perror("PIPE3\n");
if(strchr(bufor_p3,53)!=NULL) printf("Jestem 3 i dostałem 15\n");
else if(strchr(bufor_p3,56)!=NULL) printf("Jestem 3 i dostałem 18\n");
else if(strchr(bufor_p3,48)!=NULL) printf("Jestem 3 i dostałem 20\n");
}
int main(){
(...)
pipe(pm1);
pipe(pm2);
pipe(pm3);
signal(15,obslugam);
signal(18,obslugam);
signal(20,obslugam);
if((PID1=fork())==0) {
close(pm1[1]);
signal(10,obsluga1);
}
else if((PID2=fork())==0) {
close(pm2[1]);
signal(10,obsluga2);
signal(15,obsluga2);
signal(18,obsluga2);
signal(20,obsluga2);
}
else if((PID3=fork())==0){
printf("\nJestem procesem nr 2. Oto moj PID: %d\n\n",PID2);
close(pm3[1]);
signal(10,obsluga3);
}
else{
close(pm1[0]);
close(pm2[0]);
close(pm3[0]);
}
(...)
}
我嘗試過,但是找不到錯誤的地方。 感謝您的幫助。
我找不到我犯錯的地方。
錯誤是忽略了signal
(2)手冊頁中第一段的內容。
signal()的行為在UNIX版本之間有所不同,並且在歷史上在Linux的不同版本中也有所不同。 避免使用它:改為使用sigaction(2)。 請參閱下面的可移植性。
手冊頁繼續描述了不同的Unix實現signal
()的各種方式。 它描述了原始的UNIX行為,該行為也被System V Unix所采用,即在通過signal
()安裝了信號處理程序之后,一旦傳遞了信號,信號便會重置為SIG_DFL
。
然后,手冊頁指出以下內容:
Linux上的情況如下:
- 內核的signal()系統調用提供了System V語義。
結論:
1)使用系統調用時,如signal
(),重要的是閱讀其手冊頁。
2) SIGUSR1
第一次在Linux上調用自定義信號處理程序時,該信號處理程序將重置為SIG_DFL
。
3)然后,如果沒有其他事情發生,則第二次接收到該信號時,該過程將終止,因為其SIG_DFL
動作將終止該過程的信號。
4) SIGUSR1
的SIG_DFL
操作將終止該過程。 因此,您的進程第二次收到此信號時,它將終止。 這似乎是您所看到的行為。
5)當然可以在收到SIGUSR1
后立即重新安裝信號處理程序,但是正如手冊頁所述,沒有什么阻止該進程在有機會重新安裝信號處理程序之前接收到SIGUSR1
。
6)由於這些原因,手冊頁指示您改用sigaction
(2)。
7)在Linux上,更好的選擇是使用signalfd(2) 。 當然,這是特定於Linux的API。
此外,該示例代碼還具有至少兩個其他錯誤:
char bufor_p2[2]={0};
if(read(pm2[0],&bufor_p2,2)==-1)perror("PIPE2\n");
if(strchr(bufor_p2,53)!=NULL) printf("Jestem 2 i dostałem 15\n");
這里有兩個錯誤。 該代碼似乎從管道讀取了兩個字符,並希望它們將被完整讀取。
第一個錯誤是,當從管道或設備讀取多個字節時,不能保證您將成功讀取請求的字節數。 在這種情況下,您可能最終只讀取一個字節。 當應用程序讀取的字節數少於請求的字節數時,應用程序將負責繼續進行相應的操作,通常會再次嘗試讀取其余數據。
Linux內核可以保證這種情況在Linux上永遠不會發生,但是從技術上講這是一個錯誤。 寫入管道或設備也是如此。 所示代碼的其他部分嘗試向管道寫入一個以上的字節,並假定此操作將成功。
在健壯的應用程序中,應准備從管道,套接字或某些其他設備讀取或寫入的所有嘗試,以解決讀取或寫入的字節少於請求的字節的可能性,然后重試。
這里的第二個錯誤是從管道讀取了兩個字節,並將其放入兩個字符的數組中,然后使用strchr
()對其進行檢查。
根據代碼的其余部分,預期的兩個字節是兩個十進制數字,表示信號編號。
strchr
()需要以null結尾的字符串。 當然,兩字節字符數組中的兩個字節不會以空值結尾。 這將導致不確定的行為。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.