1.getpid函数
1.1函数原型
pid_t getpid(void); //返回当前进程Pid
pid_t getppid(void); //返回父进程Pid
- pid:类似于身份证,代表每一个进程
1.2 例子
int main()
{
__pid_t pid; // 定义一个变量接收Pid
pid = getpid();
printf("this process pid is %d , parent pid is %d\n",pid,getppid());
return 0;
}
运行结果:
2.Fork函数
2.1函数原型
pid_t fork(void);
- 作用:程序一开始只有一个进程,使用fork过后创建一个一模一样的进程,一起执行fork过后的代码,而fork之前的代码是由父进程进行执行的
返回值:fork函数拥有两个返回值
- =0:当前进程为子进程
- 0:当前进程为父进程
- ‐1,出错
2.2图示
注:程序运行到fork后会执行创建两个一样的父子进程,父进程跟fork前的进程是一样的,包括pid与ppid,父进程运行结束过后,跳转到fork()返回值的位置,运行子进程,子进程是父进程的拷贝,执行代码直到结束
2.3例子
int main()
{
__pid_t pid; // 定义一个变量接收Pid
pid = getpid(); //获取进程的Pid
fork(); //创建一个父进程,一个子进程,共同执行下面代码
printf("current pid is %d\n",getpid());
return 0;
}
运行结果:
画图表示:
- 运行的顺序应该是:main函数开始经过fork执行父进程,父进程执行结束回到fork返回值的位置执行子进程,到最后程序结束
2.4例2
int main()
{
pid_t pid; // 定义一个变量接收Pid
pid_t pid2;
pid = getpid();
printf("before fork pid is %d\n",pid);
fork();
pid2 = getpid();
if(pid == getpid())
{
printf("this is father : %d \n",getpid());
}
else
{
printf("this is chiild : %d \n",getpid());
}
return 0;
}
运行结果:
2.5返回值
fork会有两个返回值,大于0是代表此时是父进程,小于0代表此时是子进程
int main()
{
pid_t pid; // 定义一个变量接收Pid
pid_t pid2;
pid = getpid();
printf("before fork pid is %d\n",pid);
fork();
pid2 = getpid();
if(pid == getpid())
{
printf("this is father : %d \n",getpid());
}
else
{
printf("this is chiild : %d \n",getpid());
}
return 0;
}
运行结果:
由此可以发现,父进程的fork返回值是子进程的PID,子进程的返回值是0
2.6作用域
int main()
{
pid_t pid; // 定义一个变量接收Pid
pid_t retpid;
pid = getpid();
int data = 10;
printf("before fork pid is %d\n",pid);
retpid = fork(); //接收fork的返回值
if(retpid>0)
{
printf("this is father : %d \n",retpid);
}
else
{
printf("this is chiild : %d retpid = %d \n",getpid(),retpid);
data+=10;
}
printf("data is %d\n",data);
return 0;
}
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PuqSJZXG-1684341251753)(进程.assets/image-20230512151904802.png)]
3.Fork应用
大多数应用场景在服务器:类似于QQ,有一个用户登录就会有一个新进程被创建
场景:模拟用户输入,如果输入的是1创建一个新进程,否则什么都不做
int main()
{
pid_t retpid;
int data = 0; // 用户输入
while (1)
{
printf("plese input num:\n");
scanf("%d", &data);
if (data == 1)
{
retpid = fork(); // 输入为1创建一个进程
if (retpid > 0)
{
}
else if (retpid == 0)
{
while (1)
{
printf("wati conncet: pid = %d\n", getpid());
sleep(3);
}
}
}
else
{
printf("nothing doing now\n");
}
}
return 0;
}
运行结果:
4.Vfork函数
4.1vfork与fork的区别
- 直接使用父进程的空间,不进行多余的拷贝
- 先执行子进程,当子进程使用exit函数退出之后执行父进程
- 存储空间是共享的
4.2 例1
int main()
{
pid_t retpid;
retpid = vfork(); // 接收vfork的返回值
if (retpid > 0)
{
while (1)
{
printf("this is father pid = %d\n", getpid());
sleep(2);
}
}
else
{
while (1)
{
printf("this is chilid pid = %d\n", getpid());
sleep(2);
}
}
return 0;
}
运行结果:
4.3当子进程执行三次后退出
int main()
{
pid_t retpid;
int cnt = 0;
retpid = vfork(); // 接收vfork的返回值
if (retpid > 0)
{
while (1)
{
printf("this is father pid = %d\n", getpid());
sleep(2);
printf("cnt is %d\n",cnt);
}
}
else if(retpid == 0)
{
while (1)
{
printf("this is chilid pid = %d\n", getpid());
sleep(2);
cnt++;
if(cnt == 3)
{
_exit(-1);
}
}
}
return 0;
}
运行结果:
由于是vfork不进行拷贝,所以父进程可以使用子进程的资源