SIGCHID訊號 詳解
1.父程序可以監測子程序的以下三種事件; 每次狀態改變,子程序會發SIGCHID給父程序
· 子程序終止(即子程序死亡)
· 子程序停止(即子程序暫停)
· 子程序恢復(即子程序從暫停中恢復執行)
2.若sigaction---sigqueue中註冊了SIGCHLD訊號(訊號的傳送和安裝)
1.sigaction使用了巨集SA_NOCLDSTOP:
一旦父程序為SIGCHLD訊號設定了這個標誌位,那麼子程序停止和子程序恢復這兩件事情,就不會向父程序傳送SIGCHLD訊號了。 但是子程序切換為SIGCONT時還是會給父程序傳送SIGCHLD訊號。
2.sigaction使用了巨集SA_NOCLDWAIT:
如果父程序為SIGCHLD設定了SA_NOCLDWAIT 標誌位,那麼子程序退出時,就不會進入殭屍狀態,而是直接自行了斷。
對於Linux而言,子程序轉換切換為SIGSTOP.SIGCONT.SIGKILL時都會給父程序傳送SIGCHLD訊號。這點和上面的 SA_NOCLDSTOP 略有不同。
3. 示例程式碼
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <strings.h> #include <string.h> #include <sys/types.h> #include <sys/shm.h> #include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <signal.h> #define ERR printf("ERR: %d\n", __LINE__) #define CUR printf("CUR: %d\n", __LINE__) // signal函式安裝的訊號處理函式 void sig_child(int signum) { printf("sig: sig_child\n"); } // 無SA_SIGINFO標誌時,安裝的訊號處理函式 //void sa_handler(int signum) //{ //printf("sig: sa_handler, no SA_SIGINFO\n"); //} // 有SA_SIGINFO標誌時,安裝的訊號處理函式 static void _handle(int signum, siginfo_t *info, void *ucontext) { printf("sig: sa_handler, have SA_SIGINFO\n"); } int main(int argc, char **argv) { int ret; int signum, cldpid, cnt; struct sigaction act; union sigval sigval; // 父程序註冊sigchild訊號 signal(SIGCHLD, sig_child); ret = fork(); if (ret < 0) { ERR; return -1; } else if(!ret) { cldpid = getpid(); printf("cldpid = %d\n", cldpid); ret = fork(); if (ret < 0) { ERR; return -1; } else if(!ret) { //grandson CUR; kill(cldpid, SIGSTOP); sleep(1); CUR; kill(cldpid, SIGCONT); sleep(1); CUR; kill(cldpid, SIGKILL); // 子程序在接收到這個訊號後終止 sleep(1); exit(0); } // child cnt = 3; while(cnt--) // 捕捉孫程序傳送的3個SIGSTOP.SIGCONT.SIGKILL訊號 pause(); exit(0); } // parent cnt = 3; while(cnt--) // 監測子程序狀態改變後傳送的SIGCHLD訊號 pause(); // SA_NOCLDSTOP標誌時, 子程序狀態變為停止和子程序恢復時,不會向父程序傳送SIGCHLD 訊號 printf("------------------------------------------------\n"); signal(SIGCHLD, SIG_DFL); memset(&act, 0, sizeof(act)); act.sa_sigaction = (void (*)(int, siginfo_t *, void *))_handle; // 有SA_SIGINFO標誌時,安裝的訊號處理函式 act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO | SA_RESTART; sigaction(SIGCHLD, &act, NULL); ret = fork(); if (ret < 0) { ERR; return -1; } else if(!ret) { cldpid = getpid(); printf("cldpid = %d\n", cldpid); ret = fork(); if (ret < 0) { ERR; return -1; } else if(!ret) { //grandson CUR; sigval.sival_int = getpid(); sigqueue(cldpid, SIGSTOP, sigval); sleep(1); CUR; sigqueue(cldpid, SIGCONT, sigval); sleep(1); CUR; sigqueue(cldpid, SIGKILL, sigval); // 子程序在接收到這個訊號後終止 sleep(1); exit(0); } // child cnt = 3; while(cnt--) // 捕捉孫程序傳送的3個SIGSTOP.SIGCONT.SIGKILL訊號 pause(); exit(0); } CUR; cnt = 1; //cnt = 2; // 這個會使pause();阻塞, 因為設定了SA_NOCLDSTOP標記, 子程序切換到停止和終止狀態時不會給父程序傳送訊號 while(cnt--) // 再次監測子程序狀態改變後傳送的SIGCHLD訊號 pause(); CUR; // SA_NOCLDWAIT標誌時, 子程序狀態變為停止會向父程序傳送SIGCHLD訊號 printf("------------------------------------------------\n"); signal(SIGCHLD, SIG_DFL); memset(&act, 0, sizeof(act)); act.sa_sigaction = (void (*)(int, siginfo_t *, void *))_handle; // 有SA_SIGINFO標誌時,安裝的訊號處理函式 act.sa_flags = SA_NOCLDWAIT | SA_SIGINFO | SA_RESTART; sigaction(SIGCHLD, &act, NULL); ret = fork(); if (ret < 0) { ERR; return -1; } else if(!ret) { cldpid = getpid(); printf("cldpid = %d\n", cldpid); ret = fork(); if (ret < 0) { ERR; return -1; } else if(!ret) { //grandson CUR; sigval.sival_int = getpid(); sigqueue(cldpid, SIGSTOP, sigval); sleep(1); CUR; sigqueue(cldpid, SIGCONT, sigval); sleep(1); CUR; sigqueue(cldpid, SIGKILL, sigval); // 子程序在接收到這個訊號後終止 sleep(1); exit(0); } // child cnt = 3; while(cnt--) // 捕捉孫程序傳送的3個SIGSTOP.SIGCONT.SIGKILL訊號 pause(); exit(0); } cnt = 3; while(cnt--) // 再次監測子程序狀態改變後傳送的SIGCHLD訊號 pause(); while(1); // 第3個子程序退出後, 自行了斷, 不會變為殭屍程序 return 0; }
4. 執行結果
[email protected]_hua_shu:/work/nfs_root/qt_fs_new/2system_pro/sig$ cldpid = 11319
CUR: 64
sig: sig_child
CUR: 66
sig: sig_child
CUR: 68
sig: sig_child
------------------------------------------------
CUR: 122
cldpid = 11321
CUR: 106
CUR: 109
CUR: 111
sig: sa_handler, have SA_SIGINFO
CUR: 127
------------------------------------------------
cldpid = 11323
CUR: 151
sig: sa_handler, have SA_SIGINFO
CUR: 154
sig: sa_handler, have SA_SIGINFO
CUR: 156
sig: sa_handler, have SA_SIGINFO
[email protected]_hua_shu:/work/nfs_root/qt_fs_new/2system_pro/sig$
[email protected]_hua_shu:/work/nfs_root/qt_fs_new/2system_pro/sig$ ps
PID TTY TIME CMD
10775 pts/12 00:00:00 bash
11318 pts/12 00:00:03 a.out
11319 pts/12 00:00:00 a.out <defunct>
11321 pts/12 00:00:00 a.out <defunct>
11325 pts/12 00:00:00 ps // 說明最後一個程序並沒有變為殭屍程序