GEEK学习笔记— —Linux中fork()函数

来源:互联网 发布:数据库里配置怎么打开 编辑:程序博客网 时间:2024/04/30 21:06

基本知识

一个进程调用fork()函数后,会通过系统调用创建一个与原来进程几乎完全相同的进程,但如果初始参数或者传入的变量不同,两个进程可以做不同的事。

使用fork函数得到的子进程从父进程的继承了整个进程的地址空间,包括:进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设置、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等。
子进程与父进程的区别在于:
1、父进程设置的锁,子进程不继承;
2、各自的进程ID和父进程ID不同;
3、子进程的未决告警被清除
4、子进程的未决信号集设置为空集。

fork()函数调用一次,能够返回两次,它可能有三种不同的返回值:
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;

fork出错可能有两种原因:
1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。
2)系统内存不足,这时errno的值被设置为ENOMEM。

与clone() 函数比较

fork() 函数复制时将父进程的所以资源都通过复制数据结构进行了复制,然后传递给子进程,所以 fork() 函数不带参数;
clone() 函数则是将部分父进程的资源的数据结构进行复制,复制哪些资源是可选择的,这个可以通过参数设定,所以 clone() 函数带参数,没有复制的资源可以通过指针共享给子进程

实例

下面的都是刷题遇到的题目,鉴于有很多简单的题目,这里只给出稍微需要思考一下的题目。

题目1(阿里)

int main(){    fork()||fork();}

解答

fork()给子进程返回一个零值,而给父进程返回一个非零值;

在main这个主进程中,首先执行 fork() || fork(), 左边的fork()返回一个非零值,根据||的短路原则,前面的表达式为真时,后面的表达式不执行,故包含main的这个主进程创建了一个子进程,

由于子进程会复制父进程,而且子进程会根据其返回值继续执行,就是说,在子进程中, fork() ||fork()这条语句左边表达式的返回值是0, 所以||右边的表达式要执行,这时在子进程中又创建了一个进程,

即main进程->子进程->子进程,一共创建了3个进程。

题目2(人人网)

int main(int argc, char* argv[]){   fork();   fork() && fork() || fork();   fork();}

一共创建几个进程?

解答

1、A&&B||C
A为假,跳过B,判断C
A为真,判断B,若B为真,跳过C
若B为假,判断C

2、fork()函数父进程返回子进程ID;子进程返回0
第一条语句新增1个,目前共有2个进程
第二条语句新增4*2个,目前共有10个进程
这里写图片描述
第三条语句,此时已有进程1+1+4*2个,所以新增10个,目前共有20个进程。

题目3(腾讯)

for (int i = 0; i < 2; i++){    fork();    printf("-");}

解答

其实通过上面的讲解和题目,相信你应该很容易算出6个,但是!但是实际答案是8!!这里有个陷阱,“-”在缓冲区并没有立即被输出。那么会导致什么结果呢?那么父进程的输出缓冲会被子进程复制,从而导致多次输出。盗用网上的图说明一下,下图是整个过程图,图中相同颜色的是同一个进程,加阴影和双边框的那两个子进程就是复制了父进程标准输出缓中区里的的内容。
这里写图片描述

1 0