你的代碼的有些清理後的版本成爲MCVE(Minimal, Complete, Verifiable Example):
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
static volatile sig_atomic_t count = 0;
static void handler(int sig)
{
assert(sig == SIGCHLD);
count++;
}
int main(void)
{
signal(SIGCHLD, handler);
for (int i = 0; i < 4; i++)
{
if (fork() == 0)
{
exit(16 * (i + 1));
}
}
int corpse;
int status;
while ((corpse = wait(&status)) != -1 || errno == EINTR)
{
if (corpse == -1 && errno == EINTR)
printf("Interrupted by a signal\n");
else
printf("Child %d exited with status 0x%.4X\n", corpse, status);
}
printf("Count = %d\n", count);
return 0;
}
當在Mac上運行的MacOS塞拉利昂10.12.4與GCC 6.3.0運行,我上了主題的變化的:
Child 74003 exited with status 0x1000
Child 74004 exited with status 0x2000
Child 74005 exited with status 0x3000
Child 74006 exited with status 0x4000
Count = 4
在這個機器上(現代15" 2016年的MacBook Pro),我總是似乎得到的是作爲輸出 - 按順序爲孩子進程ID,與精心剪裁的退出狀態
。
當我改變了處理程序是這樣的(銘記的how to avoid calling printf()
in a signal handler的限制 - 是的,我知道我可以鍵入STDIN_FILENO
,而不是一些人1
S的):
static void handler(int sig)
{
assert(sig == SIGCHLD);
count++;
char s[2] = { count + '0', '\n' };
write(1, "SH: count = ", sizeof("SH: count = ")-1);
write(1, s, 2);
}
然後輸出改爲更多的東西像這樣:
SH: count = 1
SH: count = 2
Child 74113 exited with status 0x1000
Child 74114 exited with status 0x2000
SH: count = 3
Child 74115 exited with status 0x3000
SH: count = 4
Child 74116 exited with status 0x4000
Count = 4
這表明信號處理程序在循環過程中的不同時間被調用。 BSD信號處理程序(和macOS或Darwin有些基於BSD)傾向於重新啓動系統調用而不是中斷。因此,我所看到的不一定是您在不同平臺上看到的內容。
例如,在一個Ubuntu 16.04 LTS VM上運行,我得到的輸出:
SH: count = 1
Child 13310 exited with status 0x4000
Child 13309 exited with status 0x3000
Child 13308 exited with status 0x2000
Child 13307 exited with status 0x1000
Count = 1
然而,隨着信號處理的另一適應 - 恢復的信號處理,信號處理,因爲傳統通過signal()
設定處理程序(非BSD)的行爲是被稱爲處理函數之前默認的復位,並檢查書面因爲Linux已經到位警告,如果你忽略write()
返回值的字節數:
static void handler(int sig)
{
//assert(sig == SIGCHLD);
signal(sig, handler);
count++;
char s[2] = { count + '0', '\n' };
int nb = write(1, "SH: count = ", sizeof("SH: count = ")-1);
assert(nb == sizeof("SH: count = ")-1);
nb = write(1, s, 2);
assert(nb == 2);
}
然後輸出成爲:
SH: count = 1
Child 13838 exited with status 0x4000
SH: count = 2
Child 13837 exited with status 0x3000
SH: count = 3
Child 13836 exited with status 0x2000
SH: count = 4
Child 13835 exited with status 0x1000
Count = 4
所以,你可以看到,你看到的結果取決於您運行代碼的平臺上,並在handler()
功能究竟是如何寫的。
信號如何發送? –
@ Jean-BaptisteYunès信號將在子進程退出時發送。 – Dude
對不起,我沒有注意到它是SIGCHILD ... –