该程序已在C中编译并在Ubuntu上编译。我的脚本创造了两个孩子。第一个记录他的pid静态var。创建第二个孩子并向父母发送信号。
父母接收信号并在此转弯发送给第一个孩子。但是第一个孩子没有收到这个信号。函数sig_handlerr从未被调用。
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <time.h>
# include <signal.h>
# include <sys/mman.h>
static pid_t* pidt;
// handler signal père
void sig_handler(int signo)
{
if (signo == SIGUSR1) {
printf("SIG HANDLER received SIGUSR1 by process %dn", getpid());
printf("-> Envoie du signal SIGUSR1 au fils %dn", pidt[0]);
// le père envoie un signal au premier fils
kill(pidt[0], SIGUSR1);
}
}
// handler signal fils
void sig_handlerr(int signo)
{
if (signo == SIGUSR1) {
printf("SIG HANDLER2 received SIGUSR1 by process %dn", getpid());
}
}
int main(int argc, char* argv[]) {
printf("pid du processus père %dn", getpid());
pidt = mmap(NULL, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (fork()==0) {
printf("1 processus fils %dn", getpid());
pidt[0]=getpid();
printf("pid enregistré= %dn", pidt[0]);
signal(SIGUSR1, sig_handlerr);
exit(0);
}
wait(NULL);
signal(SIGUSR1, sig_handler);
if (fork()==0) {
printf("2 processus fils %d", getpid());
// il envoie un signal SIGUSR1 au processsu père
printf("-> envoie SIGUSR1 au père %dn", getppid());
kill(getppid(), SIGUSR1); // envoie un signal SIGUSR1 au processus père
exit(0);
}
wait(NULL);
printf("nn------ Fin du programme -------");
return EXIT_SUCCESS;
}
你能解释我为什么吗?
您有很多错误,其中最重要的是:
-
您的第一个子进程在致电
signal
后立即退出,父母在开始第二个过程之前等待它。这意味着,到父母到达第一个孩子的信号时,第一个孩子已经不再存在了。使用sigsuspend
使父母和第一个孩子睡觉,直到信号到达,并在所有其他工作完成后才致电父母的wait
。 -
通常在信号处理程序中调用
printf
并不安全。但是,如果信号到达时该程序在sigsuspend
中睡觉,则可以。使用sigprocmask
确保SIGUSR1
仅在sigsuspend
呼叫中可传递。(您可以在Linuxsignal-safety(7)
manpage中找到可以安全调用的功能列表。) -
而不是用共享记忆段做聪明的事情,父母应该保存孩子的pids
fork
返回给它。 -
您应该使用
sigaction
,而不是signal
。 -
您没有检查任何错误。
-
您没有检查孩子是否成功退出。
好吧,直到第一个孩子结束后,父进程才会发送任何信号(因此,它没有机会代表它行动)。它只是创建一个子进程,该过程将其pID注册在数组pidt[0]
中(在与孩子共享的内存段中的此数组)并为SIGUSR1
信号安装一个信号处理程序(无用,因为IT exit()
s之后(IT)几乎没有时间接收信号,但是阅读更多,它不能)。然后,父母 wait()
s第一个孩子的死者(这是错误的)...此后只有一个过程。
然后,父进程安装信号处理程序并创建第二个孩子。它是由子进程进行的kill()
,您可以看到信号处理程序执行后的输出。由于没有第一个孩子还活着,因此没有机会收到信号,也没有机会看到预期的输出(您不会说这是期望的,但我猜是:))
$ a.out
pid du processus père 3095
1 processus fils 3097
pid enregistré= 3097
pid du processus père 3095
2 processus fils 3098-> envoie SIGUSR1 au père 3095
pid du processus père 3095
SIG HANDLER received SIGUSR1 by process 3095
-> Envoie du signal SIGUSR1 au fils 3097
------ Fin du programme -------$ _
(看,最后一条消息的末尾没有n
,因此您在其之后立即获得提示)
注意
孩子对父母的最终杀戮可以使父母使用的wait()
SYSCALL等待中断第二个孩子(您不检查其返回值),因此,最终的printf()
可以在第二个孩子的实际出口之前被执行(孩子除了exit()
之外什么也没做任何事情,因此在孩子的最终退出后什么都没观察到,但是您也必须检查一下)。
关于在父信号处理程序中发送的信号....三思而后行:您已经启动了第二个孩子(这是将第一个信号发送给父母的孩子)在第一个孩子患有exit(2)
ED ,因此没有可能接收信号。您不会检查kill(2)
SYSCALL的结果代码,因为它将告诉您目标过程不存在。
以下代码修复损坏的零件...首先,父母无法等待孩子死亡。在安装信号处理程序后,孩子必须还活着并等待信号(这是pause(2)
所做的,等待信号到达):
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <time.h>
# include <signal.h>
# include <sys/mman.h>
static pid_t* pidt;
// handler signal père
void sig_handler(int signo)
{
if (signo == SIGUSR1) {
printf("SIG HANDLER received SIGUSR1 by process %dn", getpid());
printf("-> Envoie du signal SIGUSR1 au fils %dn", pidt[0]);
// le père envoie un signal au premier fils
kill(pidt[0], SIGUSR1);
}
}
// handler signal fils
void sig_handlerr(int signo)
{
if (signo == SIGUSR1) {
printf("SIG HANDLER2 received SIGUSR1 by process %dn", getpid());
}
}
int main(int argc, char* argv[]) {
printf("pid du processus père %dn", getpid());
pidt = mmap(NULL, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (fork()==0) {
printf("1 processus fils %dn", getpid());
pidt[0]=getpid();
printf("pid enregistré= %dn", pidt[0]);
signal(SIGUSR1, sig_handlerr);
pause();
exit(0);
}
signal(SIGUSR1, sig_handler);
if (fork()==0) {
printf("2 processus fils %d", getpid());
// il envoie un signal SIGUSR1 au processsu père
printf("-> envoie SIGUSR1 au père %dn", getppid());
kill(getppid(), SIGUSR1); // envoie un signal SIGUSR1 au processus père
exit(0);
}
wait(NULL);
printf("nn------ Fin du programme -------");
return EXIT_SUCCESS;
}
您将获得以下输出:
$ a.out
pid du processus père 3301
2 processus fils 3304-> envoie SIGUSR1 au père 3301
pid du processus père 3301
1 processus fils 3303
pid enregistré= 3303
SIG HANDLER2 received SIGUSR1 by process 3303
pid du processus père 3301
SIG HANDLER received SIGUSR1 by process 3301
-> Envoie du signal SIGUSR1 au fils 3303
------ Fin du programme -------$ _
(同样,在最后一条消息之后提示:))
您的代码和我的代码和我的代码之间的区别在下面,以说明差异:
$ diff -c a-old.c a-new.c
*** a-old.c 2017-12-18 11:54:51.000000000 +0100
--- a-new.c 2017-12-18 11:43:21.000000000 +0100
***************
*** 42,50 ****
pidt[0]=getpid();
printf("pid enregistré= %dn", pidt[0]);
signal(SIGUSR1, sig_handlerr);
exit(0);
}
- wait(NULL);
signal(SIGUSR1, sig_handler);
--- 42,50 ----
pidt[0]=getpid();
printf("pid enregistré= %dn", pidt[0]);
signal(SIGUSR1, sig_handlerr);
+ pause(); /* wait for a signal to arrive */
exit(0);
}
signal(SIGUSR1, sig_handler);