谁能帮我一步通过下面的C代码来理解输出应该是什么?
int x = 0;
pid_t pid;
int flag=1;
void handler1(int sig) {
x=x+1;
printf("%dn",x);
fflush(stdout);
exit(0);
}
void handler2(int sig) {
x = x + 2;
flag = 0;
waitpid(-1,NULL, 0);
}
int main() {
signal(SIGUSR1, handler1);
signal(SIGCHLD, handler2);
printf("%dn",x);
fflush(stdout);
if ((pid = fork()) == 0) {
while(1) {};
}
kill(pid, SIGUSR1);
while(flag) {};
printf("%dn",x);
fflush(stdout);
exit(0);
}
我认为输出应该是"213",但我不确定。
从技术上讲,它是未定义的,因为您使用来自信号处理程序的stdio函数。我会用单个write
替换printf
/fflush
组合(但实际冲洗流的奖励点)。退出信号处理程序也被认为是不好的形式。
同时,x
和flag
都需要变成volatile
。
- 发生的第一件事是打印
- 则进程为
fork()
ed。 - 将
SIGUSR1
传递给子进程,并在其中调用处理程序。处理程序在子对象中增加x
,并打印1
。 - 子进程退出,父进程的
SIGCHLD
处理程序被调用,父进程的x
副本(仍然为0)增加2。 - 父进程退出循环轮询
flag
,并打印当前值2
。
x
,而它的值仍然是0
。所以输出应该是012
这段代码是一个父线程'main()'和一个由'fork()'创建的子线程的故事。
故事从父线程开始,它用信号处理程序设置舞台,然后打印出x
的值,该值先前被初始化为0
。
然后,父线程生成"子"线程,向子线程发送SIGUSR1信号,然后陷入while循环。跳出循环的唯一方法是清除父元素的副本。"国旗"变量。
现在故事转向了孩子;事实证明,子进程能够继承父进程的所有财富,包括它自己的'x'副本(由父进程初始化为0)。
不幸的是,在出生后,孩子进入了一个无限循环。子进程退出循环的唯一方法是处理一个"信号"。幸运的是,对于孩子来说,父母碰巧做到了。如前面所述,父进程在父进程陷入循环之前已经向子进程发送了SIGUSR1信号。
因此,子线程冲到'handler1()',(父线程先前指定为'SIGUSR1'处理程序)。在那里,它将其(子线程)的'x'副本从0增加到1,并打印新值(1)。打印后,子线程被'exit()'函数简单地终止。
…但这孩子的故事还不止这些!当孩子咽下最后一口气时,它会向父进程发出一个'SIGCHLD'信号(多亏了'exit()'函数)。然后,孩子被放置到最后的休息。(安息吧,孩子,安息吧)
同时,父进程被困在循环中;但是'SIGCHLD'信号导致父进程运行到'handler2()',(父进程先前指定为'SIGCHLD'处理程序)。在处理程序中,父节点首先将'x'的副本从0更改为2。但你猜家长发现了什么?导致父进程陷入循环的"标志"。因此,父进程清除标志,这将(在从'handler2()'返回循环后)将父进程从循环中释放出来。
然而,在离开'handler2()'之前,父线程做最后一次检查,以确保丢失已久的'子'线程已死。当发现是这种情况时,父进程悲伤地返回到它被限制的循环中。
重新进入循环时,父进程发现标志已清除,并跳出循环!然后输出它的'x'副本(2),然后终止它自己。
。
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
int x = 0;
pid_t pid;
int flag=1;
/* SIGUSR1 Signal Handler. */
/* Executed by child thread when parent sends a 'SIGUSR1' signal to child. */
void handler1(int sig)
{
/* Change the child's copy of 'x' from 0 to 1. */
x=x+1;
/* Print the value of x [1]. 'flush()' ensures that it prints -now- */
printf("%dn",x);
fflush(stdout);
/* A 'SIGCHLD' signal is sent to the parent, and thread self-terminates. */
exit(0);
}
/* SIGCHLD Signal Handler. */
/* Executed by the parent (main) thread when child sends a 'SIGCHLD' signal to parent. */
void handler2(int sig)
{
/* Parent changes it's copy of 'x' from 0 to 2 */
x = x + 2;
/* Clear 'flag', allowing parent 'main()' thread to break out of 'while()' loop. */
flag = 0;
/* Wait for all child processes to terminate. */
waitpid(-1,NULL, 0);
}
int main()
{
/* Register 'handler1()' as the 'SIGUSR1' signal handler. */
signal(SIGUSR1, handler1);
/* Register 'handler1()' as the 'SIGCHLD' signal handler. */
signal(SIGCHLD, handler2);
/* Print the value of x [0]. 'flush()' ensures that it prints -now- */
printf("%dn",x);
fflush(stdout);
/* 'fork()' creates a 'child' process. */
if ((pid = fork()) == 0)
{
/* This "infanate loop" is executed by the 'child' process only. */
while(1)
{};
}
/* Parent 'main()' thread sends a 'SIGUSR1' signal to the 'child' process. */
kill(pid, SIGUSR1);
/* Loop, waiting for child to clear 'flag' */
while(flag)
{};
/* Print the value of x [2]. 'flush()' ensures that it prints -now- */
printf("%dn",x);
fflush(stdout);
/* Terminate parent 'main()' thread. */
exit(0);
}
输出: 0
1
2