设为首页 加入收藏

TOP

有意思的进程创建函数fork()的问题
2015-07-20 17:46:57 来源: 作者: 【 】 浏览:2
Tags:有意思 进程 创建 函数 fork 问题

在做某个公司的笔试题的时候遇到了这么一个问题,描述如下:

如下代码会输出多少个"-"字符?

#include
  
   
#include
   
     #include
    
      int main() { int i; for(i=0;i<2;i++) { fork(); printf("-\n"); } return 0; }
    
   
  

在这里只做一个引子,下面稍微介绍一下fork()然后再解决这个问题。


fork()函数

#include
  
   

/*返回值:子进程中返回0,父进程中返回子进程ID,出错返回-1*/
pid_t fork(void);

  
由fork创建的新进程被称为子进程(child process)。fork函数被调用一次,但返回两次。子进程的返回值是0,而父进程的返回值则是新进程的进程ID。 将子进程ID返回给父进程的理由是:因为一个进程的子进程可以有多个,并且没有一个函数使一个进程可以获得其所有子进程的进程ID。 fork使子进程得到返回值0的理由是:一个进程只会有一个父进程,所以子进程总是可以调用getpid以获得其父进程的进程ID。

使fork失败的两个主要原因是:系统中已经有了太多的进程,或者该实际用户ID的进程总数超过了系统限制。

fork有下面两种用法:

(1)一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的--父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达。

(2)一个进程要执行一个不同的程序。这对shell是常见的情况。子进程从fork返回后立即调用exec。

归结起来说就是是实现多线程。C语言多线程实现需要自己控制来实现,这个比Java要复杂。


注意:fork确实创建了一个子进程并完全复制父进程,但是子进程是从fork后面那个指令开始执行的。对于原因也很合乎逻辑,如果子进程也从main开头到尾执行所有指令,那么它执行到fork指令时也必定会创建一个子子进程,子子孙孙无穷尽也,如此下去,这个小小的程序就可以创建无数多个进程可以把你的电脑搞瘫痪,所以fork作者肯定不会这么做。

在此,我们还是举一个最经典的fork的代码示例:

#include
  
   
#include
   
     #include
    
      int main() { pid_t pid = fork();//程序从这里开始分岔,父子进程都从这一句开始执行一次 if(pid > 0) { sleep(2); printf( "this is parent process:process id is %d\n",getpid() ); } else if(pid==0) { printf( "this is child process:process id is %d\n",getpid() ); } else { printf("error!\n"); } return 0; } 
    
   
  

结果:

\


现在回到开头的程序上,到底输出多少个"-"?原来的代码将循环解析一下成为如下格式:

int main()
{
	fork();
	printf("-\n");
	fork();
        printf("-\n");
	return 0;
}

分析:首先父进程A执行第一个fork()函数,然后生成了一个子进程B,此时A和B同时也就是并发执行,都执行printf("-");先输出了两个"-",然后进程A和进程B由都执行fork()函数,因此A又创建了子进程C,B创建了子进程D,现在一共有四个进程ABCD,然后同时执行下面的printf("-");,打印四次,输出四个"-",一共输出6个"-"。

如下图:

\

可见,一共执行了6次printf("-")。


OK,我们知道了这个之后再来看一道有意思的问题:

#include
  
   
int main()
{
  fork();
  fork()&&fork()||fork();
  fork();
}
  
请问有多少个进程?

分析:解决这个问题主要注意三点:1.子进程是从fork后面那个指令开始执行的;2.fork父子进程的不同返回值;3对于"a&&b"如果a为0,那么不会再执行b。

用语言来描述实在是太复杂,上一张,希望读者能够看懂:

\


最后的进程总数看有多少个节子点就行了。很明显一共是20个。关键点就是在树的第三层,C和D都是子进程,那么它俩返回的值都是0,因此"&&"后面的表达式就不会执行,之后执行最后一个fork()函数。但是A和B两个父进程返回值大于0,因此会执行后面的"fork()||fork()"。分析结束,如果有问题,可以留言。


参考资料:

《UNIX高级环境编程


转载请注明出处:http://blog.csdn.net/lavorange/article/details/38961247


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Linked List Cycle [leetcode] 下一篇《Effective C++》学习笔记(八)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·哈希表 - 菜鸟教程 (2025-12-24 20:18:55)
·MySQL存储引擎InnoDB (2025-12-24 20:18:53)
·索引堆及其优化 - 菜 (2025-12-24 20:18:50)
·Shell 中各种括号的 (2025-12-24 19:50:39)
·Shell 变量 - 菜鸟教 (2025-12-24 19:50:37)