一、进程的创建
1、fork函数
在Linux中,fork函数是非常重要的函数,它从已存在的进程中创建一个新进程。新进程为子进程,原进程为父进程。
返回值:
子进程返回0,父进程返回子进程id,出错返回-1。
什么时候使用fork呢?当一个父进程希望复制自己,使父子进程同时执行不同的代码段。或者一个进程要执行一个不同的程序。
那么,进程调用fork函数后,控制权转移到内核中的fork代码后,内核做了什么呢?
如下图:
如上图,内核分配新的内存块和内核数据结构给子进程,将父进程部分数据结构内容拷贝至子进程,添加子进程到系统进程列表当中,fork返回,开始调度器调度。
那么调用完之后呢?就有了两个二进制代码相同的进程,而且运行到相同的地方。但每个进程之后就可以开始自己的旅程。
用代码解释一下:
编译后执行结果:
一共有三行输出,注意观察。进程4966先打印before消息,然后打印After消息。而4967进程只打印了After消息。这是因为上文中提到的,fork之前父进程独立执行,fork后产生子进程,分别执行。而谁先执行完全由调度器决定。
2、vfork函数
同样可以创建子进程但是与fork有区别:
vfork用于创建一个子进程,而子进程和父进程共享地址空间,fork的子进程具有独立地址空间
vfork保证子进程先运行,在它调用exec或(exit)之后父进程才可能被调度运行。
看一个例子:
结果:
子进程直接改变了glob的值,证明在同一块空间中运行。
二、进程等待
1、进程等待的必要性
子进程若已退出,父进程若不等待,可能造成僵尸进程,造成内存泄漏。父进程也应知道子进程完成的如何,是否正常退出。且可通过进程等待的方式,回收子进程资源,获取子进程退出信息。
2、进程等待的方法
返回值:
如上图可知:
1、wait
返回值:成功返回被等待进程pid,失败返回-1
参数:输出型参数,获取子进程退出状态,不关心则可以设置为NULL
2、waitpid
返回值:当正常返回的时候waitpid返回收集到的子进程id
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在
参数:
pid:
pid=-1,等待任一个子进程,与wait等效。
pid>0,等待其进程id与pid相等的子进程
status:
WIFEXITED:若为正常终止子进程返回的状态,则为真(查看进程是否正常退出)
WEXITSTATUS:若WIFEXITED非零,提取子进程退出码(查看进程的退出码)
注:不能以简单的整型来看待,可以看作位图,只研究status的低16比特位,如下图:
options:
WNOHANG:若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的id。
举例:进程的阻塞等待方式,即option取0:
结果:
三、进程终止
进程退出有几种场景,代码运行完毕,结果正确或不正确;代码异常终止
1、进程正常终止
从main返回 调用exit _exit
2、进程异常退出
ctrl+c,信号终止
现在来认识一下_exit与exit函数
3、_exit函数
参数:status定义了进程的终止状态,父进程通过wait来获取该值
4、exit函数
exit函数最后也会调用_exit,但在调用之前,还做了其他工作
举例子如下:
结果:
5、return
return是一种更常见的退出进程方法,执行return n的等同于执行exit(n)