[英]Should child processes also be unblocking blocked SIGCHLD signals?
我正在嘗試了解阻塞和解除阻塞信號的工作原理,並且我正在嘗試了解以下代碼段。 具體來說,我正在查看第 28 行(在代碼中注釋): int a = sigprocmask(SIG_UNBLOCK, &mask, NULL);
,也就是信號在孩子中暢通無阻的地方。
教科書我得到的代碼從說,代碼使用信號以確保該程序執行它的附加功能阻斷(簡化為printf("adding %d\\n", pid);
)其刪除功能之前(簡化為printf("deleting %d\\n", pid);
)。 這對我來說很有意義; 通過阻塞SIGCHLD
信號,然后在執行 add 函數后解除阻塞,我們確保在執行 add 函數之前不會調用處理程序。 但是,我們為什么要在孩子中解鎖信號呢? 這不是通過立即解除阻塞來消除阻塞的全部意義,允許子進程在父進程添加之前刪除它嗎?
但是,無論我是否注釋掉該行,輸出(在代碼之后描述)都是相同的,這意味着這顯然不是發生的情況。 教科書上說:
“請注意,孩子繼承了他們父母的阻塞集,所以我們必須小心在調用
execve
之前解除孩子中的SIGCHLD
信號。”
但在我看來,解除阻塞仍然會導致處理程序被調用。 這條線到底有什么作用?
void handler(int sig) {
pid_t pid;
printf("here\n");
while ((pid = waitpid(-1, NULL, 0)) > 0); /* Reap a zombie child */
printf("deleting %d\n", pid); /* Delete the child from the job list */
}
int main(int argc, char **argv) {
int pid;
sigset_t mask;
signal(SIGCHLD, handler);
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask, NULL); /* Block SIGCHLD */
pid = fork();
if (pid == 0) {
printf("in child\n");
int a = sigprocmask(SIG_UNBLOCK, &mask, NULL); // LINE 28
printf("a is %d\n",a);
execve("/bin/date", argv, NULL);
exit(0);
}
printf("adding %d\n", pid);/* Add the child to the job list */
sleep(5);
printf("awake\n");
int b = sigprocmask(SIG_UNBLOCK, &mask, NULL);
printf("b is %d\n", b);
sleep(3);
exit(0);
}
輸出:
adding 652
in child
a is 0
Wed Apr 24 20:18:04 UTC 2019
awake
here
deleting -1
b is 0
但是,我們為什么要在孩子中解鎖信號呢? 這不是通過立即解除阻塞來消除阻塞的全部意義,允許子進程在父進程添加之前刪除它嗎?
不可以。每個進程都有自己的信號掩碼。 一個新進程繼承了它的父進程的信號掩碼,但只是在它繼承了父進程的內存內容的相同意義上——子進程獲得了相當於一個獨立副本的內容。 它對該副本的修改不會反映在父副本中,反之亦然。 如果不是這種情況,那么系統中的所有進程將共享一個信號掩碼。
只有父級不能過早收到SIGCLD
,因此只有父級需要阻止該信號。
[...] 教科書上說:
“注意孩子繼承了他們父母的阻塞集,所以我們必須小心在調用execve之前解除孩子中的SIGCHLD信號。”
但在我看來,解除阻塞仍然會導致處理程序被調用。
同樣,“繼承”是指繼承副本,而不是指共享相同的掩碼。
這條線到底有什么作用?
它在子SIGCLD
中解除對SIGCLD
的阻塞——同樣,對父SIGCLD
沒有影響——以防它被阻塞會干擾子進程將要執行的/bin/date
的行為。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.