目录
一、进程退出
#include <stdlib.h>
void exit ( int status );
#include <unistd.h>
void _exit ( int status );
退出进程 是 调用exit函数 ,C语言标准库中 exit() 函数 , linux操作系统提供 _exit()。它们都可以用于进程退出,但是它们是由区别的。如下面的示意图:
C语言中的 exit()函数执行,在调用 _exit()系统函数之前,会刷新 I/O缓冲,关闭文件描述符。 而直接调用 _exit() 函数,会直接终止进程。
代码示例,解释exit 与 _exit 的区别:
1.调用 exit 函数
/*
#include <stdlib.h>
void exit(int status);
#include <unistd.h>
void _exit(int status);
status参数:是进程退出时的一个状态信息,父进程回收子进程资源的时候,可以获取到。
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("hello\n");//带换行符\n,内部会自动刷新IO缓冲区
printf("world");//写到缓冲区中,但是没进行IO刷新,把数据刷新到显示台
exit(0);
return 0;
}
执行结果如下:
把没有带 \n 的word也输出到显示终端,因为调用exit()函数,在结束进程前,会进程缓冲区IO刷新。
2.调用 _exit 函数
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello\n");//带换行符\n,内部会自动刷新IO缓冲区
printf("world");//写到缓冲区中,但是没进行IO刷新,把数据刷新到显示台
_exit(0);
return 0;
}
执行结果如下:
直接调用 _exit()函数结束进程, 不会在结束前,将缓冲区数据进行IO刷新到显示终端。
二、孤儿进程
父进程运行结束,但子进程还在运行(未运行结束),这样的子进程就 称为 孤儿进程(Orphan Process)。( 没了原来父进程的 子进程 )
每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为 init ,而 init进程会循环地 wait() 释放它的已经退出的子进程的资源。 这样,当一个孤儿进程凄凉地结束了其生命周期的时候, init 进程就会处理释放孤儿进程的PCB资源。
因此孤儿进程并不会有什么危害。
孤儿进程,代码示例:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid = fork();
if(pid>0)
{
printf("I am parent process,pid:%d,ppid:%d\n",getpid(),getppid());
}
else if(pid == 0)
{
//当前是子进程
sleep(4);
printf("I am child process, pid:%d ppid:%d\n",getpid(),getppid());
}
//父子进程都会执行
for(int i =0 ;i<3;++i)
{
printf("i:%d ,pid:%d\n",i,getpid());
sleep(1);
}
return 0;
}
执行结果:
父进程的运行都结束了, 子进程还没有运行结束。 并且子进程的 父进程ppid变为了1。 就是子进程是孤儿进程,内核就把孤儿进程的父进程设置为 init ,init进程的id是1,而 init进程会循环地 wait() ,回收它的已经退出的子进程的资源。
3157是当前终端进程的ID,当orphan主进程,结束后,会由后端转向前端,即当前终端。那么为什么子进程的数据也会显示在当前终端呢? 是以为子进程 在fork的时候,会与父进程共享一些数据,文件描述符表等,所以显示在当前终端。
三、僵尸进程
每个进程结束之后, 都会释放自己地址空间中的用户区数据,内核区的 PCB 没有办法自己释放掉,需要父进程去释放。
进程终止时,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程。
僵尸进程不能被 kill -9 杀死,这样就会导致一个问题,如果父进程不调用 wait()或 waitpid() 的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的(0~32767),如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程,此即为僵尸进程的危害,应当避免。
代码示例:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid = fork();
if(pid>0)
{
while(1)
{
printf("I am parent process,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
}
}
else if(pid == 0)
{
//当前是子进程
printf("I am child process, pid:%d ppid:%d\n",getpid(),getppid());
}
//父子进程都会执行
for(int i =0 ;i<3;++i)
{
printf("i:%d ,pid:%d\n",i,getpid());
sleep(1);
}
return 0;
}
执行结果:
通过ps aux ,查看进程状态: