起因
在复习Linux操作的时候发现了本科中涉及不深的知识点,在此记录一下。
本科中,和进程有关的知识大概有进程的调度策略,进程和线程的关系。我能记得的差不多就是这些了。
今天,我就在Linux中,使用C语言,来复现一下进程理论。为什么一定要是Linux系统呢?Linux系统编译C方便一点,而且我目前电脑上就有VSCode+WSL的环境,我相信其他环境一定也可以整理进程理论。
网上的第一个例子
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
int ret = fork();
if(ret == 0)
{
printf("I am child : %d, ret: %d\n", getpid(), ret);
}
else if(ret > 0)
{
printf("I am father : %d, ret: %d\n", getpid(), ret);
}
else
{
perror("fork");
return 1;
}
return 0;
}
————引用信息————
版权声明:本文为CSDN博主「空白」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43697119/article/details/102767088
保存为fork.c文件,使用gcc -o fork. fork.c
命令编译后,会得到fork的可运行文件,./fork
就可以运行了。以下是运行结果:
I am father : 680, ret: 681
I am child : 681, ret: 0
提问1
代码自上而下执行,怎么会有两个输出?如果之前没有听过fork,那你会不会把这个理解为多线程?
回答1
这里面最可疑的就是函数fork(定义在头文件unistd中)。当调用fork函数后,内核就会经行一系列的操作。这些操作我分成两个角度说,毕竟这里太乱了。
广义上
- 调用fork的进程称为父进程。
- 父进程触发fork函数后,会创建一个新进程(也可能创建失败),新进程称为子进程。
- 父进程和子进程是相对的,如果只对一个进程讨论,那么就没有父子的说法了。
- 父进程和子进程差不多相同,但是有细微差别。
细节上
出发fork函数后,内核(我们常常叫做系统
)做的事情:
- 分配新的内存块和内核数据结构给子进程
- 将父进程的部分数据结构内容拷贝至子进程
- 添加子进程到系统进程列表当中
- fork返回,开始调度器调度
提问 2
怎么操作子进程?代码中的ret(fork函数的返回值)是句柄嘛?拿到句柄就可以操作该进程嘛?还是类似Java中线程那样,通过一个类或者一个函数,把新进程要做的事情包裹起来?
回答 2
- 进程不是线程,fork创建的是进程,不是线程。虽然上面说到父进程,和子进程,但是从进程和线程概念上来说,父进程和子进程又是并列的。 他们都有一个标记进程的
pid
。代码中使用了getpid()
函数,返回一个int类型的pid,我们还可以调用getppid()
函数返回该进程的父进程pid。 - fork函数调用后,源代码会被粗暴的复制一份(不太严谨,我也没有深究)。见下图(来源:CSDN微微啦啦),然后两边独立执行。
- fork函数的特点就是:调用一次返回两次。我们这么理解,在父进程(B)中fork的返回值与子进程(A)中fork的返回值是不一样的。B中的pid会返回当前进程号,A中pid是0。于是,并行的两段代码通过pid判断各自执行自己的那部分代码。
总结
下面我贴出我实验的代码,并作出解释。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t fpid; //fpid表示fork函数返回的值
int count = 0;
fpid = fork();
if (fpid < 0)
printf("error in fork!");
else if (fpid == 0)
{
while (1)
{
sleep(2);
printf("child %d\tfather %d\n", getpid(),getppid());
count+=5;
printf("[child] count value is \t%d\n",count);
}
}
else if(fpid>0)
{
while (1)
{
sleep(3);
printf("father %d\n", getpid());
count+=1;
printf("[father]count value is \t%d\n",count);
}
while (waitpid(-1, NULL, WNOHANG) > 0);
}
printf("统计结果是: %d\n", count);
return 0;
}
}
运行结果
child 701 father 700
[child] count value is 5
father 700
[father]count value is 1
child 701 father 700
[child] count value is 10
father 700
[father]count value is 2
child 701 father 700
[child] count value is 15
child 701 father 700
[child] count value is 20
father 700
[father]count value is 3
child 701 father 700
[child] count value is 25
father 700
[father]count value is 4
child 701 father 700
[child] count value is 30
child 701 father 700
...
可以看到变量count
出现了不同的数值,父进程和子进程是分开的。