目录
1、概念:
fork函数从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。
使用fork()要包含头文件:#include <unistd.h>
pid_t id = fork(void);
返回值:子进程中返回0,父进程返回子进程id,出错返回-1
进程调用fork,当控制转移到内核中的fork代码后执行以下操作:
1、分配新的内存块和内核数据结构给子进程2、将父进程部分数据结构内容拷贝至子进程3、添加子进程到系统进程列表当中4、fork返回,开始调度器调度
2、程序测试:
当一个进程调用
fork
之后,就有两个二进制代码相同的进程。而且它们都运行到相同的地方。但
两个进程拥有不同的pid
代码如下:
int main()
{
pid_t id = fork();
if(id == 0)
{
//child
printf("I am child, pid: %d, ppid: %d\n", getpid(),getppid());
sleep(1);
}
else if(id > 0)
{
printf("I am father, pid: %d\n", getpid());
sleep(1);
}
return 0;
}
由输出结果可见,子进程与父进程又不同的pid但是子进程的ppid就是父进程的pid。
3、写时拷贝:
通常,父子代码共享,父子不再写入时,数据是共享的,当任意一方试图写入,便以写时拷贝的方式创建一份副本。
4、fork常规用法:
1、一个进程希望创建一个子进程。使父子进程同时执行不同的代码段。
2、一个进程要执行另一个不同的进程,例如子进程从fork返回后调用exec函数。
5、fork失败的原因:
1、系统中有太多的进程
2、实际用户的进程数超过了限制
6、进程终止:
进程退出场景:
1、代码运行完毕,结果正确。
2、代码运行完毕,但结果不正确。
3、代码异常终止。
7、进程常用退出方法:
正常终止:(可以通过 echo $? 查看进程退出码)
1、从main的return返回
2、调用exit
3、调用_exit
exit实际上也是调用了_exit,exit退出前会冲刷缓冲,关闭流,如果缓冲区中有内容就会显示出来,但_exit不会。
异常退出:
ctrl+c退出
8、等待进程 :
1、wait函数:
#include<sys/types.h>
#include<sys/wait.h>
pid_t rid = wait(int*status);
返回值:
成功返回被等待进程
pid
,失败返回
-1
。
参数:
输出型参数,获取子进程退出状态
,
不关心则可以设置成为
NULL
2、waitpid函数:
pid_t rid = waitpid(pid_t pid, int *status, int options);
//案例
pid_t rid = waitpid(id, &status,0)//当options为0时,父进程是阻塞等待的方式
pid_t rid = waitpid(id, &status,WNOHANG)//当options为WHOHANG时,父进程是非阻塞等待的方式
返回值:
当正常返回的时候
waitpid
返回收集到的子进程的进程
ID
;
如果设置了选项
WNOHANG,
而调用中
waitpid
发现没有已退出的子进程可收集
,
则返回
0
;
如果调用中出错
,
则返回
-1,
这时
errno
会被设置成相应的值以指示错误所在;
参数:
pid
:
pid=-1, 等待任一个子进程。与 wait 等效。pid>0. 等待其进程 ID 与 pid 相等的子进程。
status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)WEXITSTATUS(status): 若 WIFEXITED 非零,提取子进程退出码。(查看进程的退出码)
options:
WNOHANG: 若 pid 指定的子进程没有结束,则 waitpid() 函数返回 0 ,不予以等待。若正常结束,则返回该子进程的ID 。