前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux的fork使用

Linux的fork使用

作者头像
小二三不乌
发布2018-09-30 09:30:53
3.5K0
发布2018-09-30 09:30:53
举报

Linux的fork使用

fork函数可以算是Linux里有点不好明白的函数了,调用一次,返回两次,虽然在平时的写法中,有基本固定的写法,但是有时候看起来还是有些让人头疼的。这里就把关于fork函数好好整理一下

函数介绍

功能:fork函数是从一个已经存在的进程中创建一个新的进程,新的进程称为子进程,原来的进程称为父进程。 参数:无 返回值: 成功:子进程中返回 0,父进程中返回子进程 ID。pid_t,为无符号整型。 失败:返回 -1。

失败的两个主要原因是: 1)当前的进程数已经达到了系统规定的上限,这时 errno 的值被设置为 EAGAIN。 2)系统内存不足,这时 errno 的值被设置为 ENOMEM。

测试的例子

下面是一个简单的创建子进程的例子。

代码语言:javascript
复制
#include <iostream>
#include <unistd.h>
#include <sys/types.h>

int main(){
    int pid=1;
    pid=fork();
    if(0==pid){ //pid为0,表示为子进程
        cout<<"我是子进程,我的pid是:"<<getpid()<<endl;
    }
    else if(pid>0){ //pid>0表示父进程,此时返回值为子进程的pid
        cout<<"我是父进程,我的pid是"<<getpid()<<endl;
    }
    else {  //fork 失败
        cout<<"fork失败"<<endl;
    }
}

从上面的例子可以看出,fork函数会有两个返回值,一个是在子进程中返回0,一个是在父进程中返回子进程的pid。因此在编程过程中,需要判断这个值的返回值来判断当前是父进程还是子进程。

fork进程的原理

使用 fork() 函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间:包括进程上下文(进程执行活动全过程的静态描述)、进程堆栈、打开的文件描述符、信号控制设定、进程优先级、进程组号等。子进程所独有的只有它的进程号,计时器等(只有小量信息)。因此,使用 fork()函数的代价是很大的。

日常使用fork

简单来说, 一个进程调用 fork() 函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。

实际上,更准确来说,Linux 的 fork() 使用是通过写时拷贝 (copy- on-write) 实现。写时拷贝是一种可以推迟甚至避免拷贝数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只用在需要写入的时候才会复制地址空间,从而使各个进行拥有各自的地址空间。也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享

子进程是父进程的一个复制品,可以简单认为父子进程的代码一样的。一般来说,在 fork() 之后是父进程先执行还是子进程先执行是不确定的。这取决于内核所使用的调度算法。

因此,在实际的使用过程中,一般都需要对fork()的返回值进行判断,看我们操作的是父进程还是子进程。

一般的操作:同时创建多个子进程

不对的例子:父进程会生成 n(n+1)/2+1个子进程,N 为循环次数,本例中共有 7 个子进程, 但实际上只有 3 个是父进程产生的,其余都为子进程 fork()出来的。父进程fork了3个进程,第一个子进程执行完之后又fork了2个进程,第2个子进程fork了1个进程。

代码语言:javascript
复制
int main(){
    pid_t p1,p2;
    int i;
    int N=100;
    for(int i=0;i<=N;++i){
        if((p1=fork())==0){
            cout<<"子进程1:"<<getpid()<<endl;
            //return 0;  //很关键的地方,为什么需要返回呢
        }
        wait(p1,NULL,0); //父进程等待p1子进程执行后才能继续fork其他子进程
        cout<<"这是父进程: "<<getpid()<<endl;
    }
}

正确的使用Linux中的用fork()由一个父进程创建同时多个子进程 的格式如下:

代码语言:javascript
复制
int main(){
    pid_t p1,p2;
    int i;
    int N=100;
    for(int i=0;i<=N;++i){
        status=fork();
        if(status==0||status==1) break;//每次循环时,如果发现是子进程就直接从创建子进程的循环中跳出来,不让你进入循环,这样就保证了每次只有父进程来做循环创建子进程的工作
        if (status == -1)
        {
          //error
        }
        else if (status == 0) //每个子进程都会执行的代码

        {
          //sub process
        }
        else
        {
          //parent process
        }
    }
}

无聊的问题

1.下面的程序,不算 main这个进程自身,到底创建了多少个进程啊?

代码语言:javascript
复制
int main(int argc, char* argv[])
{
   fork();
   fork() && fork() || fork();
   fork();
}

每fork一次就翻倍

代码语言:javascript
复制
  fork(); //2个
   fork() && fork() || fork();
//A&&B||C
//A为假,跳过B,判断C-----------------------2
//A为真,判断B,若B为真,跳过C-----------1
//若B为假,判断C ------------2
   fork(); //2

总共有: 2(2+1+2)2=20 不算自己的话有20-1=19个

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-03-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Linux的fork使用
    • 函数介绍
      • 测试的例子
        • fork进程的原理
          • 日常使用fork
            • 一般的操作:同时创建多个子进程
          • 无聊的问题
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档