浅谈Linux下进程创建、进程终止、进程等待

本节主要内容:

1.进程创建
2.进程终止
3.进程等待

进程创建

1.fork()函数:

#include <unistd.h>
pid_t fork(void);
//返回值:子进程中返回0,父进程返回子进程id,出错返回-1
  • fork()函数的作用是创建一个进程,并且fork()函数是一个系统调用
  • 父进程调用fork()函数创建子进程后,子进程拷贝父进程PCB,父子进程是独立的两个进程
  • 子进程从fork()函数之后的代码开始运行,通过程序计数器 (保存了程序即将要执行的下一条指令) 和上下文数据 (保存了寄存器当中的值) 知道自己如何运行

详细介绍可以看上篇文章:浅谈fork()函数

2.vfork()函数

  1. vfork()函数也可以创建子进程,和fork()不同的是:vfork()函数创建出来的子进程拷贝父进程PCB,并且子进程当中的内存指针和父进程指向同一个虚拟地址空间,即父子进程共用一个虚拟地址空间。
  2. 存在的问题:调用栈混乱
  3. vfork()函数通过让子进程先运行,子进程运行完成之后,再让父进程运行来解决这个问题
  4. 目前很少用了

网上抄的一段,可以再理解理解:
为什么会有vfork,因为以前的fork 很傻, 它创建一个子进程时,将会创建一个新的地址
空间,并且拷贝父进程的资源,而往往在子进程中会执行exec 调用,这样,前面的拷贝工
作就是白费力气了,这种情况下,聪明的人就想出了vfork,它产生的子进程刚开始暂时与
父进程共享地址空间(其实就是线程的概念了),因为这时候子进程在父进程的地址空间中
运行,所以子进程不能进行写操作,并且在儿子 霸占”着老子的房子时候,要委屈老子一
下了,让他在外面歇着(阻塞),一旦儿子执行了exec 或者exit 后,相 于儿子买了自己的
房子了,这时候就相 于分家了。

原文链接:https://blog.csdn.net/jianchi88/article/details/6985326

进程终止

1.概念

也就是进程退出,分为以下两个场景

1.代码执行完了,从main函数return返回,运行结果可能正确也可能不正确

2.代码没有执行完,直接崩溃掉了 (内存访问越界,解引用空指针,double free, ctrl+c,kill 命令)

2.程序结束的方式

1.main函数return返回
2.调用exit()函数:库函数,C库当中提供给程序员的函数
3.调用_exit()函数:系统调用,操作系统提供给程序员的函数

void exit(int status); 
//status:进程在在退出的时候,可以指定退出码是多少
//echo $?   //能够获取最后一个终止进程的退出码

浅谈Linux下进程创建、进程终止、进程等待

exit()函数与_exit()函数区别就如图所示:

1.exit()函数会执行用户自定义清理函数

自定义清理函数:int atexit(void\*(\*fuction)(void));
参数是函数指针:返回值为void,参数为void
作用:调用atexit()函数,参数为一个函数的地址,会将这个函数的地址保存下来,等待进程退出的时候再来调用这个函数。

2.exit()函数会刷新缓冲区

为什么exit()函数会刷新缓冲区而_exit()不会?

  • 1.缓冲区是C库当中维护的,并不是内核维护的
  • 2.如果直接调用_exit()函数,直接执行内核代码,就不会刷新缓冲区了
  • 3.如果调用了exit()函数,在进程结束之前,会先将缓冲区中的数据进行刷新,在结束进程

如何刷新缓冲区?

  • 从main()函数return返回
  • \n可以刷新缓冲区
  • fflush函数可以强制刷新缓冲区
  • exit()函数也会刷新缓冲区

进程等待

1.作用:防止僵尸进程的产生

2.接口:pid_t wait(int* status)

status为输出型参数,由操作系统为其赋值

这里status是int类型,占四个字节,我们只用到后面两个字节,实际有效的也就是后两个字节

进程正常退出时:

浅谈Linux下进程创建、进程终止、进程等待

进程异常退出时:

浅谈Linux下进程创建、进程终止、进程等待

3.使用的方式

创建一个子进程,子进程执行正常逻辑,父进程调用wait()函数进行阻塞等待,当子进程退出的时候,父进程由于在等待,所以子进程也就不会变成僵尸进程了。

  • 阻塞:当调用函数需要等待一定条件成熟的时候,函数才进行返回;条件不成熟,则一直等待。
  • 非阻塞:当调用函数需要等待一定条件成熟的时候,函数返回;条件不成熟,则报错返回

再梳理一下僵尸进程的产生:

子进程退出,父进程收到子进程的退出信号SIGCHLD,但是父进程对SIGCHLD信号是忽略处理的,所以导致子进程资源无法释放。
而进程等待,会将父进程收到的SIGCHLD信号进行处理,子进程就会正常退出,不会造成僵尸进程的产生。

此外,还有一个进程等待函数waitpid();

参数模型:

pid_t waitpid(pid_t pid, int* status, int options);

参数含义:

pid:告诉waitpid函数需要等待哪个子进程
pid = -1 表示等待任意子进程;

pid > 0 表示等待指定子进程,子进程的进程号就是传入的pid的值

status:和wait中status参数含义一致

options:设置waitpid函数是阻塞还是非阻塞的

0 : 非阻塞
WNOHANG:非阻塞,即当子进程没有退出的时候,waitpid函数就会返回报错

waitpid(pid>0, status, 0) ===>就相当于wait()函数
wait()函数就是调用waitpid函数实现的

猜你喜欢

转载自blog.51cto.com/14289099/2643804