本文学习自《TCP/IP网络编程》
------
使用fork函数创建进程
#include <stdio.h>
#include <unistd.h>
int gval = 10;
int main(int argc,char *argv[])
{
pid_t pid;
int lval = 20;
gval++,lval+=5;
pid = fork();
if(pid == 0)
gval+=2,lval+=2;
else
gval-=2,lval-=2;
if(pid == 0)
printf("Child Proc:[%d,%d]\n",gval,lval);
else
printf("Parent Proc:[%d,%d]\n",gval,lval);
return 0;
}
pid为0,说明是子进程
pid不为0,说明是父进程
在pid = fork();这句执行前,gval值为11,lval值为25。
pid = fork()执行后:
子进程中gval,lval加2
父进程中gval,lval减2
------
通过fork函数创造出的子进程如何终止?
应该向创建子进程的父进程传递子进程的exit参数值或return语句的返回值。
------
向exit函数传递的参数值和main函数的return语句返回的值都会传递给操作系统。
操作系统必须等到把这些值传递给产生该子进程的父进程,才会销毁子线程。
所以,如果子进程已经通过exit或return传递值给操作系统,但这些值没有传递给父进程,此时的子进程就叫僵尸线程。
------
如何向父进程传递这些值呢?
操作系统不会主动把这些值给父进程。
必须父进程主动请求时,操作系统才会传递这些值给父进程。
------
当父进程执行结束时,父进程被销毁,同时子进程也被销毁。
------
僵尸进程的验证
#include <stdio.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
pid_t pid = fork();
if(pid == 0)
{
puts("Hi,I am a child process");
}
else
{
printf("Child Process ID:%d\n",pid);
sleep(10);
}
if(pid == 0)
printf("End child process\n");
else
printf("End parent process\n");
return 0;
}
这段程序中,子进程很快就运行完毕,return 0了。
而父进程因为sleep(10),睡眠了10s。
此时操作系统已经收到了子进程传递的值,而父进程没有去获取该值,所以此时子进程就是僵尸进程。
当主进程也运行完成后,主线程和子线程同时被销毁。
---------
为了销毁子进程,父进程必须主动请求获取子进程的返回值。
共有两种方法可以做到。
(1)
#include <sys/wait.h>
pid_t wait(int * statloc)
stat:status
loc:location:(计算机内存里的)地址
调用成功时返回终止的子进程ID,失败时返回-1.
调用此函数时如果已经有子进程终止,那么子进程终止时传递的返回值将保存到该函数的参数所指的内存空间。
但是函数参数指向的单元中还包含其他信息,所以需要通过宏进行信息的分离。
WIFEXITED:宏:子进程正常终止时返回true(wifexited)
WEXITSTATUS:宏:返回子进程的返回值(wexitstatus)
示例:
if(WIFEXITED(status))
{
puts("Normal termination!");
printf("Child pass num:%d",WEXITSTATUS(status));
}
如果子进程正常终止,输出子进程的返回值。
------
修改之前的僵尸进程示例,使子进程正常退出。