进程创建函数fork()
函数原型: pid_t fork(void)
头文件: #include <unistd.h>
函数功能: 创建一个子进程
返回值: 1. -1 创建失败
2. 0 返回的是子进程
3. >0 返回的是父进程,返回值是子进程ID
函数特性: 1. 调用一次,会有两个返回值
2. 先返回哪个值,不确定,一般先返回父进程
3. 用户可以通过延时函数,决定进程的执行先后顺序。
4. 创建后,子进程复制父进程空间,这个空间子进程所独有的只有它的进程号、计数器和资源使用,其他的和父进程
空间一样,两个空间相互独立,互不干涉即使全局变量,在子进程中不会随父进程中变量的值的改变而改变。
函数框架:
1 #inlcude <stdio.h> 2 #include <unisd.h> 3 int main() 4 { 5 pid_t pid; 6 //父进程独有 7 pid = fork(); 8 //父子进程共有 9 if(pid < 0) 10 { 11 printf(“establish error!\n”); 12 return -1; 13 } 14 else if(pid == 0) 15 { 16 //子进程独有 17 //子进程 18 } 19 else if(pid > 0) 20 { 21 //父进程独有 22 //父进程 23 } 24 //父子进程共有 25 }
分析:独有的只会运行一次,共有的会运行两次。
进程切换: 1. 通过延时类函数(可控): sleep(s延时) usleep(us延时)
2. 时间片到了(不可控)
注意: 延时会让程序处于等待态,所谓等待态,就是先去运行已经处于就绪态的程序,什么时候延时时间到了,程序
就会处于就绪态。等其他程序运行完,或者时间片到了,再切换回来,从上次的断点处继续运行。两个进程之间
没有优先级关系,不存在打断关系,只有子进程运行完了,或者进入等待态,或者时间片到了才会进入父进程。
示例: 下面的代码示例,如果没有时间片的影响,在进入子进程以后,会一直卡在子进程,永远不会再回到父进程,因
受时间片的影响,还会过一段时间就切换回父进程。
#include <stdio.h> 2 #include <unistd.h> 3 int main() 4 { 5 int num_father = 1; 6 int num_son = 1; 7 pid_t pid; 8 pid = fork(); 9 if(pid < 0) 10 { 11 printf("error\n"); 12 return -1; 13 } 14 else if(pid == 0) 15 { 16 num_son++; 17 printf("son\n"); 18 while(1) 19 { 20 printf("num_son=%d\n",num_son); 21 } 22 } 23 else if(pid >0) 24 { 25 num_father++; 26 printf("father\n"); 27 while(1) 28 { 29 usleep(1); 30 printf("num_father = %d\n",num_father); 31 } 32 } 33 }
代码最终运行结果是:一直打印num_son,偶尔会打印num_father。原因是卡在子进程了,因为时间片到了才会切回父进程,但是很快又回到了子进程。
执行流程:1. 父进程运行后,遇到fork()之前,都是父进程独有的程序
2. 当遇到fork函数后,开始创建子进程,一般先返回父进程
3. 在进入if框架之前,fork下的程序是子进程和父进程共有的
4. 进入pid>0父进程独有的框架,如果父进程独有中无等待类操作,父进程独有的运行完,接着运行if框架外程序,
直到父进程运行完,然后再运行子进程,这时候子进程已经变为了孤儿进程。
1 #inlcude <stdio.h> 2 #include <unisd.h> 3 int main() 4 { 5 pid_t pid; 6 //父进程独有 7 pid = fork(); 8 //父子进程共有 9 if(pid < 0) 10 { 11 printf(“establish error!\n”); 12 return -1; 13 } 14 else if(pid == 0) 15 { 16 //子进程独有 17 //子进程 18 } 19 else if(pid > 0) 20 { 21 //父进程独有 22 //父进程 23 } 24 //父子进程共有 25 }
运行步骤:
运行分析: fork有两个返回值,但是返回顺序有先后关系,第一个返回值是>0,先运行的是父进程,pid>0的elseif运行结束后,
父进程就结束了,此时,子进程变成了孤儿进程,被祖先进程接收,因为会返回两个返回值,所以又会返回一个
值,程序从fork函数处又运行一遍,此时返回的是=0返回值的值,此时再运行==0的elsif。
示例代码:
创建进程程序模板:
条件: 1.避免孤儿进程和僵尸进程
2.不存在父子进程共有的,全是独有的