#include
#include
#include
#include
#include
#include
volatile int wait_flag=0;
void change_value(int para);
void stop_info(int para);
int main()
{
int pid1,pid2;
signal(2,stop_info);
wait_flag = 1;
printf("before fork child1\n");
while((pid1=fork())<0);
printf("after fork child1\n");
if(pid1>0)
{
while((pid2=fork())<0);
if(pid2>0)
{
printf("parent id is %d\n",getpid());
wait(0);
wait(0);
printf("parent is killed.\n");
exit(0);
}
else
{
signal(17,change_value);
printf("child2 id is %d\n",getpid());
while(wait_flag == 1);
printf("child2 is killed\n");
exit(0);
}
}
else
{
signal(16,change_value);
printf("child1 id is %d\n",getpid());
while(wait_flag == 1);
printf("child1 is killed\n");
exit(0);
}
}
void change_value(int para)
{
wait_flag = 0;
printf("pid: %d, wait_flag = 0\n",getpid());
}
void stop_info(int para)
{
printf("process %d: stop info!\n",getpid());
}
下面是一个结果:
> gcc -Wall fork.c -o fork
> ./fork
before fork child1
after fork child1
after fork child1
parent id is 7118
child1 id is 7119
child2 id is 7120
程序会停在这里,注意:before fork child1 打印了一次,after fork child1打印了两次
也就是说fork函数前的代码只会在父进程中执行一次
按下Ctrl + C后程序并不会退出,并出现如下:
^Cprocess 7118: stop info!
process 7119: stop info!
process 7120: stop info!
这是自然的,因为程序重新定义了停止信号:
signal(2,stop_info);
不过, 值得注意的是,
(1)Ctrl + C是向进程及其所有的子进程发送停止信号,而不止是它自己这个进程。
(2)这个函数定义在fork之前,从结果看两个子进程明显均执行了这个函数,
然而,前面已提到,fork函数之前的printf函数却只会由父进程执行一次。
当然,可以另开一个终端,用kill单独地向某一个进程发信号: kill -2 7119
process 7119: stop info!
pid: 7119, wait_flag = 0
child1 is killed
这里wait_flag已变为0,只死掉了子进程1,但是子进程2并没有死掉,可见,三个进程的wait_flag是独立的,尽管它是个全局变量
同样需要注意,wait_flag = 1语句在fork之前,这明显三个进程都执行过它, 否则,两个子进程会因为wait_flag = 0而立即退出。
问题来了:为什么printf函数却只执行一遍呢?
向子进程2发信号 kill -17 7120
pid: 7120, wait_flag = 0
child2 is killed
parent is killed.
结合书中的解释:
fork函数被调用一次,但返回两次,子进程和父进程继续执行fork调用之后的函数,子进程是是父进程的副本,
获得父进程的数据空间、堆、栈的副本,但并不共享这些存储空间部分,只共享正文段。
所以,以上的解释是错误的,wait_flag=1只由父进程执行一次, 也就是说,子进程获得副本时,
wait_flag已经变为1。所以,更准确地说,子进程获得的副本,是父进程当前状态的副本。
signal函数估计也是一样,不清楚其中的原理,不好解释。