getpid/getppid
getpid 获取当前进程id
getppid 获取当前进程的父进程的id
fork
pid_t fork()
1.为什么fork有两个返回值?
因为这两个返回值是由不同的进程return出来的,而不是由一个fork函数返回两个数。
(fork后,进程由一个变成两个,两个进程分别有一个返回值)
返回值:
<0:失败
>0:当前进程为父进程(父进程的返回值)
=0:当前进程为子进程(子进程的返回值)
2.子进程创建成功后,代码的执行的开始位置?
fork代码段的位置
3.父子进程的执行顺序?
不一定谁先谁后(看谁抢到CPU资源)
4.如何区分父子进程?
通过fork的返回值
案例1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(){
for(int i=0;i<4;i++) //仅仅在父进程中执行一次
printf("---------%d\n",i);
pid_t pid=fork();
if(pid<0){
perror("fork fail");
}
if(pid>0){ //parent process
printf("parent process,pid=%d\n",getpid());
}
if(pid==0){ //child process
printf("child process,pid=%d\n",getpid());
}
for(int i=0;i<4;i++) //在父进程和子进程中各执行一次
printf("%d\n",i);
}
[gjw@localhost 1-fork]$ gcc fork.c -o fork --std=c99 #编译代码
[gjw@localhost 1-fork]$ ./fork #执行结果
---------0
---------1
---------2
---------3
parent process,pid=117802
0
1
2
3
child process,pid=117803
0
1
2
3
案例2:循环创建number个子进程
父进程
子进程1 子进程2 子进程3 ...... 子进程number
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(){
int i;
int number=5;
pid_t pid;
for(i=0;i<number;i++){
pid=fork();
if(pid<0){
perror("fork fail");
exit(1);
}
if(pid==0)
break;
}
for(int j=0;j<number;j++){ //判断子进程是第几个孩子
if(j==i)
printf("%d process,pid=%d\n",j,getpid());
}
if(i==number) //判断父进程是哪一个:(父进程退出for循环时,i==number)
printf("parent process,pid=%d\n",getpid());
}
[gjw@localhost 1-fork]$ ./fork
0 process,pid=70113
1 process,pid=70114
2 process,pid=70115
parent process,pid=70112
4 process,pid=70117
3 process,pid=70116
写时拷贝原则write-on-copy
1.读时共享
刚fork出来之后,两个地址空间用户区数据完全相同,父子进程都指向同一块共享区域,父子进程中
都映射到共享区域中的变量(int num)
2.写时拷贝
当后续父子进程对共享区域中的变量进行不同的操作时(父进程对num++,子进程对num--),
===>发生写时拷贝原则,父子进程各自拷贝出来int大小的空间存放自己的num,因此父子进程
中的num是相互独立,互不影响的====>因此父子进程之间不能够使用全局变量进行通信。
vfork
vfork() 函数和 fork() 函数一样都是在已有的进程中创建一个新的进程,但它们创建的子
进程是有区别的。
(1)父子进程的执行顺序
fork(): 父子进程的执行次序不确定。
vfork():保证子进程先运行,在它调用 exec/exit之后,父进程才执行
(2)是否拷贝父进程的地址空间
fork(): 子进程拷贝父进程的地址空间,子进程是父进程的一个复制品。
vfork():子进程共享父进程的地址空间
(3)调用vfork函数,是为了执行exec函数;如果子进程没有调用 exec/exit, 程序会出错
vfork案例
验证1:vfork父子进程执行顺序
子进程先执行完exec或exit后
父进程才开始执行
int main(int argc, char *argv[]){
pid_t pid;
pid = vfork(); // 创建进程
if(pid < 0){ // 出错
perror("vfork");
}
if(0 == pid){
sleep(3); // 延时 3 秒
printf("i am son\n");
_exit(0); // 退出子进程,必须
}
else if(pid > 0){ // 父进程
printf("i am father\n");
}
}
执行结果:已经让子进程延时 3 s,结果还是子进程运行结束后,父进程才执行
验证2:vfork后,父子进程共享内存空间
int a = 10;
int main(int argc, char *argv[]){
pid_t pid;
int b = 20;
pid = vfork(); // 创建进程
if(pid < 0){ // 出错
perror("vfork");
}
if(0 == pid){ // 子进程
a = 100, b = 200;
printf("son: a = %d, b = %d\n", a, b);
_exit(0);
}
else if(pid > 0){
printf("father: a = %d, b = %d\n", a, b);
}
}
执行结果:子进程先执行,修改完a,b的值后,由于父子进程共享内存空间,因此会影响父进程
son: a = 100, b = 200
son: a = 100, b = 200