进程控制

进程创建

进程调用fork,当控制转移到内核中的fork代码,内核做:
1.分配新的内存块和内核数据结构给子进程
2.将父进程部分数据结构内容拷贝至子进程
3.添加子进程到系统进程列表当中
4.fork返回开始调度器调度
fork之前父进程独立执行,fork之后,父子两个执行流分别执行。fork后,谁先执行完全由调度器决定。

写时拷贝

读时共享,写时拷贝。父子代码共享,父子不在写入时,数据也是共享的,当任意一方试图写入,便以拷贝的方式各自一份副本。

fork调用失败

系统中有太多的进程
实际用户的进程超出了限制

进程终止

正常终止:
1.从main返回
2.调用exit
3._exit
异常退出:
ctrl+c,信号终止

exit函数

#include
exit(int status)

exit最后也会调用_exit再调用之前:
1.执行用户通过atexit或on_exit定义的清理函数
2.关闭所有打开的流,所有的缓存数据均被写入
3.调用_exit
return n 等同于exit(n)因为调用main的运行时函数会将main的返回值做exit的参数

wait

#include
pid_t wait(int* status)
返回值:
成功返回等待进程PID失败返回-1
参数:
输出型参数,获取子进程退出状态,不关心设置为NULL

注意事项

1.wait的调用次数必须和子进程的个数一致
wait的调用次数较少,导致僵尸进程
wait的调用次数较多,多出来的wait就会调用出错
2.如果有多个子进程,任何一个子进程结束都会触发wait返回

waitpid

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

返回值: 当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。
status: WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATU(status):WIFEXITED非零,提取子进程退出码.(查看进程的退码) options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该 子进程的ID。

status不能简单的当作整形来看待,可以当作位图来看待

注意事项

waitpid能够等待某个指定子进程的退出
waitpid(-1,NULL,0)就和wait(NULL)是等价的
非阻塞轮询式的wait
好处:能够更灵活的控制代码,充分利用等待时间去做其他事情
坏处:代码写起来更复杂

进程的程序替换

fork创建出的子进程和父进程是共用同一份代码,而事实上我们更需要创建出的子进程能够执行一份单独的代码
1.程序替换不会创建新的进程,也不会销毁进程
2.替换代码和数据(从一个可执行的程序中来)
3.原有的堆和栈中的数据就全都不要了,根据新的代码的执行过程重新构建堆和栈的内容

exec函数族

参数有差异,底层原理完全相同
execl
execlp
execle
l=>list变长参数列表
execv
execvp
execve
v=>vector数组
程序替换经常要搭配fork来使用,一旦替换就会把原来进程的代码和数据都干掉无法继续执行原来的代码了

你可能感兴趣的:(LINUX)