进程创建:
在Linux中,创建进程主要用函数fork(),vfork()。
fork()
它表示从一个已存在的进程中创建一个新的子进程,新进程为子进程,原进程则为父进程。
函数原型:
pid_t fork();
返回值:子进程返回值为0,父进程返回子进程的id,出错返回-1
进程调用fork()之后,内核需要做的事情有:
- 分配新的内核空间和数据结构给子进程
- 将父进程部分数据结构的内容拷贝给子进程
- 添加子进程到系统进程列表中
- fork返回,调度器开始调度
fork()采用的是写时拷贝技术,因为父进程与子进程的文件描述表是指向同一份的,但当子进程一旦修改某一数据时,会拷贝一份副本供子进程写入,但不会修改父进程的任何数据。
fork()的常规用法:父进程一般会创建一个子进程希望这个子进程来执行不同的代码块,类似于并发。
fork()调用失败的原因:系统中有太多进程,实际用户的进程数量超过系统限制。
代码调用:
通过代码和运行结果可以很清晰的看出fork的机制。
vfork():
用于创建一个子进程,该子进程与父进程享有共同的地址空间,而fork()的子进程具有独立的地址空间。
子进程如果修改地址空间里的任意数据,则父进程的也会改变。这就说明子进程与父进程共享地址空间。
调用代码:
结果也可以很明显的看出
进程等待
本质:父进程等待子进程,等待回收资源,以免造成资源的浪费。
等待方法:
pid_t wait(int* status);
返回值:等待成功返回子进程的id,出错返回-1
pid_t waitpid(pid_t id,int*status,int option);
返回值:当正常返回时waitpid返回收集到的子进程的进程id
如果设置了WNOHANG,调用中waitpis发现没有已退出的子进程可收集,则返回0;
如果调用出错,返回-1
如果子进程退出,调用等待方法时,会立即返回,并且释放资源,获得子进程退出信息。
如果子进程正在运行时调用了等待方法,可能会造成进程阻塞
如果子进程不存在调用等待方法,立即出错返回
代码实现:
由图可以看出,当我使用kill -9 杀掉子进程之后,父进程显示等待成功,即父进程回收资源成功。
进程程序替换
用fork创建进程之后,子进程执行的是与父进程相同的程序(但可能执行的代码分支不同),子进程往往要调用exec函数以执行另一个程序。当进程调用另一种exec函数时,该进程的用户空间代码和数据完全被新数据替换,从新程序的启动例程开始进行,调用exec不会创建新的进程,所以调用exec函数该进程的id不会被改变。所以将这类函数称为程序替换函数。
程序替换使用的是替换函数,有六种以exec开头的函数,统称exec函数。
#include<unistd.h>
int execl(const char* path,const char* arg..)
int execlp(const char* file,const char* arg..)
int execle(const char* path,const char* arg...char *const envp[])
int execv(const char* path,char *const argv[])
int execvp(const char* file,const char* argv[]..)
int execve(const char* path,const char* argv[],char* const envp[]..)
返回值:调用成功则接在新的程序,出错则返回-1。
记忆规律: