1,孤儿进程:
父进程已经运行结束,但是子进程依然在运行时,子进程被称为孤儿进程。孤儿进程会被1号祖父进程接管。
程序示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
if(pid==0)
{
int i =0;
for(i=0;i<10;i++)
{
printf("pid: %d,ppid: %d\n",getpid(),getppid());
}
}
else if(pid>0)
{
printf("pid: %d,ppid: %d\n",getpid(),getppid());
sleep(3);
exit(1);
}
else
{
printf("fork");
return 1;
}
return 0;
}
~
运行结果:
从运行结果我们可以看到,起初子进程5071的父进程为5070,在父进程退出后,其由1号进程接管,父进程变为1号进程。
2,僵尸进程
僵尸进程就是子进程已经退出,但是父进程依然在等待,并且没有收到子进程的退出码.
程序示例:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid = fork();
if(pid<0)
{
printf("fork");
return 1;
}
else if(pid>0)
{
printf("pid:%d ppid:%d\n",getpid(),getppid());
sleep(30);
}
else
{
printf("pid:%d ppid:%d\n",getpid(),getppid());
sleep(5);
exit(1);
}
}
我们可以看到,进程5561变为了z状态 ,也就是僵尸状态。
僵尸进程的危害:
僵尸进程会导致内存泄漏,
僵尸进程的父进程会一直等待其返回。
僵尸进程也有pcb,也需要资源和操作系统的维护,会导致电脑变卡。
虚拟内存机制:
子进程通过父进程fork()来创建。子进程以父进程有相同的代码。但是通过写时拷贝的技术让其拥有不同的数据空间。
代码示例:
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4
5 int g_val = 10;
6 int main()
7 {
8 pid_t pid = fork();
9
10 if(pid<0)
11 {
12 printf("fork");
13 return 1;
14 }
15 else if(pid>0)
16 {
17 printf("pid:%d, ppid:%d, g_val:%d, &g_val:%p\n",getpid(),getppid(),g_val,&g_val);
18 sleep(3);
19 }
20 else
21 {
22 g_val = 23;
24 printf("pid:%d, ppid:%d, g_val:%d, &g_val:%p\n",getpid(),getppid(),g_val,&g_val);
25 sleep(1);
27 }
28 }
~
我们可以看到,g_val的值在子进程中被修改为23,但是他的地址却与父进程中g_val的地址相同,显然与我们上面说的父子进程享有独立的数据空间不同。这是为什么呢?
在进程中,有一个虚拟内存机制,进程创建后是在虚拟内存上创建,然后虚拟内存通过页表映射到物理内存。我们说的父子进程用的不同地址空间时指在屋里内存上的不同,而打印出的是虚拟内存的地址,r如图:
从图中我们可以看出,每个进程都会对应一个虚拟内存空间,而打印出的是虚拟内存空间的地址。实际存储的是物理内存。