• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > Linux下C语言的fork()子进程函数用法及相关问题解析

Linux下C语言的fork()子进程函数用法及相关问题解析

作者:sponge 字体:[增加 减小] 来源:互联网 时间:2017-05-28

sponge 通过本文主要向大家介绍了linux的fork.c源文件,linux fork,linux fork函数,linux中fork函数,linux中fork等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

fork
fork()函数是linux下的一个系统调用,它的作用是产生一个子进程,子进程是当前进程的一个副本,它跟父进程有一样的虚存内容,但也有一些不同点。
但是,值得注意的是,父进程调用fork()后,fork()返回的是生成的子进程(如果能顺利生成的话)的ID。子进程执行的起点也是代码中fork的位置,不同的是下面这段C语言代码展示了fork()函数的使用方法:

// myfork.c

#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv) {
  while (1) {
    pid_t pid = fork();
    if (pid > 0) {
      // 主进程
      sleep(5);
    } else if (pid == 0) {
      // 子进程
      return 0;
    } else {
      fprintf(stderr, "fork error\n");
      return 2;
    }
  }
}

</div>

调用fork()函数后,系统会将当前进程的绝大部分资源拷贝一份(其中的copy-on-write技术这里不详述),该函数的返回值有三种情况,分别是:
1.大于0,表示当前进程为父进程,返回值是子进程号;
2.等于0,表示当前进程是子进程;
3.小于0(确切地说是等于-1),表示fork()调用失败。

看两个比较有意思的C语言题目。
 
第一题:计算下面代码理论上总共打印了多少行:(网易2011笔试题)

#include
#include
#include
int main(){
    int i;
    for(i = 0; i<5; i++){
        fork();
        printf("%d\n",getpid());
        fflush(stdout);
    }
}
</div>

问题解答:
这道问题并不难,最快的想法就是2+4+8+16+32,因为第一层的printf会有两个进程打印,第二层会增加到4个,以此往下,就得出62行。
 
但我这里打算采用另外一种方法,一种更加直观的方法,就是直接数出来,这样会避免大脑短路,而且对下一题目有帮助。
 
要直接数出来也很简单,只是有些繁琐,因为每循环一次,都会打印一行并且产生一个子进程,子进程又会继续循环打印并产生新的进程。我们可以在草稿纸上画一棵树,画出每个进程的子进程以及循环次数,如果你眼力够好,脑子不容易乱,这种方法很快会让你得到正确答案。但我恰好脑子不是能够保证清醒的人,画了三遍树得到的都是错误答案。
 
随后,我在纸上用了一种更简单的数据结构——队列进行计算,并且顺利得出了答案。我是这样计算的:

首先,主进程会循环5次,则我们将5压入到队列中:

queue =" 5 ";
sum = 0; //sum是总打印次数
</div>

主进程会循环5次,打印5行并且产生5个子进程,这5个子进程分别会打印5,4,3,2,1行,则我们将这5个数放入队列,并将第一个5出队列加入到sum中:

queue = " 5 4 3 2 1 ";
sum = sum + 5;
</div>

这样,我们再取队列首元素,即5,他会打印5行,并且生成4个子进程,子进程的分别会打印4,3,2,1行,我们把这4个数放入到队列中,并将第一个5出队列加入到sum中:

queue = " 4 3 2 1 4 3 2 1";
sum = sum + 5;
</div>

我们继续重复上面的工作,取首元素4,他会打印4行,并且会声称3个子进程,子进程分别打印3,2,1行,重复上面的入队列和出队列操作:

queue = " 3 2 1 4 3 2 1 3 2 1 ";
sum = sum + 4;
</div>

这样,以此重复以上的操作,当遇到元素1的时候,只有出队列而没有入队列的操作,因为只打印1行的子进程不会再循环产生新的子进程。最后,当队列中不再有元素的时候,sum就是总共打印的行数。
 
这种方法的有点是你可以很轻松、很清醒的在纸上把队列写出来并算出答案,缺点是如果你加法不好,很容易算错答案!
 

第二题:问下面的代码执行后总共产生了多少进程(不包括主进程)?(2009 EMC笔试)

#include
int main(){
    fork();
    fork() && fork() || fork();
    fork();
}
</div>

这个题目跟上一个对比起来就稍微有点难度了,因为你就算画树也有可能算错!
 
我个人感觉这个题目考察两方面的知识:1、开头所讲的fork()返回值;2、&&和||的运算。
 
让我们现讨论下&&和||的运算再来继续讨论这个题目。&&是“逻辑与”操作,如果两个操作数有一个为0,则整个式子为0。标准C中规定,如果&&运算符的左操作数为0,则不计算右操作数;如果左操作数为1,才计算右操作数。
与之类似,||操作符是“逻辑或”操作,标准C规定如果||运算符左操作数为1,则不计算右操作数;如果左操作数为0,则计算右操作数。
 
继续来看我们的题目,我们把题目中的5个fork()分别标记为A,B,C,D,E。则我们可以看到,主进程一共产生4个进程,分别产生在A,B,C,E位置上(B,C两个fork()返回值都不是0,因此B&&C不为0,因此不计算D)。让我们仍然采用上题的算法,使用一个队列:

首先,将主进程产生子进程的位置放到队列中:

queue = " A B C E ";
sum = 0;
</div>

我们从队列中取首元素A,我们分析A处产生的进程,发现它会在B, C, E三处产生子进程,我们把这三个元素插入到队列中,并将sum+1。

queue = " B C E B C E ";
sum ++;
</div>

然后,我们从队列中取出首元素B,B处产生的子进程稍稍不一样,因为子进程中B所代表的fork()返回值为0,因此C得不到执行,而D会得到执行。因此,B处产生的子进程会执行D, E,将这两个元素送入队列,sum++:

queue = " C E B C E D E ";
sum ++;
</div>

下面,我们取首元素C,分析发现,C处产生的进程会执行D, E,送入队列并且sum++:

queue = " E B C E D E D E ";
sum ++;
</div>

同上一题一样,依次这样执行,遇到E则没有元素入队列,直到最后队列为空,sum就是总共产生的进程个数。

</div>
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 浅谈Linux环境下并发编程中C语言fork()函数的使用
  • Linux下C语言的fork()子进程函数用法及相关问题解析

相关文章

  • 2017-05-28C 字符串数组排序的小例子
  • 2017-05-28C语言实现红黑树的实例代码
  • 2017-05-28浅谈c语言中类型隐性转换的坑
  • 2017-05-28一波C语言字符数组实用技巧集锦
  • 2017-05-28C语言 奇偶排序算法详解及实例代码
  • 2017-05-28纯C语言实现五子棋
  • 2017-05-28C的|、||、&、&&、异或、~、!运算符
  • 2017-05-28C语言中一些将字符串转换为数字的函数小结
  • 2017-05-28c语言中位字段与结构联合的组合使用详解
  • 2017-05-28C++通过COM接口操作PPT

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C++智能指针读书笔记
    • Linux中使用C语言实现基于UDP协议的Socket通信示例
    • DSP中浮点转定点运算--定点数的加减乘除运算
    • 用typedef定义类型详细总结
    • C++ explicit关键字的应用方法详细讲解
    • 深入ORACLE变量的定义与使用的详解
    • C语言中字符的输入输出以及计算字符个数的方法详解
    • C语言求圆周率的简单实现方法
    • 利用C++实现从std::string类型到bool型的转换
    • 哪款C语言编译器(IDE)适合初学者?

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有