zoukankan      html  css  js  c++  java
  • 进程创建

    在linux下,创建进程可以使用两个glibc函数,分别是 fork, vfork

    fork

    fork函数用来创建一个子进程,声明如下:

    #include <sys/types.h>
    #include <unistd.h>

    pid_t fork(void);

    fork函数,一次调用,两次返回。在父进程,返回值是子进程的进程ID,在子进程,返回的是0, 可以使用getppid函数获取父进程的进程号。

    fork内部调用clone系统调用。创建的子进程虽然和父进程运行在不同的内存空间,但是子进程完全复制父进程的代码和数据,刚创建成功时,两个内存空间的内容是完全一样的。这个复制使用的是写时复制。

    子进程复制了父进程的数据段、BSS、代码段、堆、栈、文件描述符,父子进程不共享这些存储。两进程会共享正文段、文件表项

    两个进程也有很多不同:

    • 进程号
    • 父进程设置的锁
    • 子进程的进程资源和CPU使用时间重置为0
    • 子进程未决信号集为空

    如果fork返回-1,表示创建进程失败,errno 被设置

    fork失败的原因有:

    • 系统创建的进程达到最大进程数目限制。这时候,最好检查一下僵尸进程
    • 系统内存使用完了

     

    子进程完全复制父进程代码

    #include <sys/types.h>
    #include <sys/unistd.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    
    
    int main()
    {
        pid_t id = -1;
    
        for (int i = 0; i < 2; i++)
        {
            id = fork();
            if (id > 0)
            {
                printf("parent pid: %d
    ", getpid());
            }
            else if (id == 0)
            {
                printf("child pid: %d
    ", getpid());
            }
            else
            {
                perror("fork");
            }
        }
    
        return 0;
    }

    这段代码执行结果是:

    parent pid: 18992
    parent pid: 18992
    child pid: 18993
    child pid: 18994
    parent pid: 18993
    child pid: 18995

    我们看到,for循环执行了两次,但是产生了4个不同的进程。循环n次,就创建 2^n 个进程

    两进程不共享数据段、堆栈

    #include <sys/types.h>
    #include <sys/unistd.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    
    
    int global_a = 20;
    
    int main()
    {
        int local_b = 30;
        int *p = new int(10);
    
        pid_t id = fork();
        if (id > 0)
        {
            global_a++;
            local_b++;
            (*p)++;
            printf("in parent pro, global_a = %d, local_b = %d, *p = %d
    ", global_a, local_b, *p);
        }
        else if (id == 0)
        {
            printf("in child pro, global_a = %d, local_b = %d, *p = %d
    ", global_a, local_b, *p);
        }
        else
        {
            fprintf(stderr, "error");
        }
    
        delete p;
    
        return 0;
    }

    输出:

    in parent pro, global_a = 21, local_b = 31, *p = 11
    in child pro, global_a = 20, local_b = 30, *p = 10

    父子进程的执行顺序是不确定的

    如果想让两个进程保持顺序,需要用到同步的方法了

    子进程继承文件描述符、共享文件表项

    #include <sys/types.h>
    #include <sys/unistd.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    
    
    int main()
    {
        FILE *pf = fopen("fil.txt", "w");
    
        pid_t id = -1;
    
        id = fork();
        if (id > 0)
        {
            fprintf(pf, "parent pro")
        }
        else if (id == 0)
        {
            fprintf(pf, "parent pro")
        }
    
        fclose(pf);
    
        return 0;
    }

     父子进程都写了内容到文件中,没有产生覆盖,说明父子进程共享文件偏移,就是文件表项。

    子进程继承信号处理

    #include <sys/types.h>
    #include <sys/unistd.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <signal.h>
    
    
    void func(int sig)
    {
        printf("%d
    ", sig);
    }
    
    int main()
    {
        signal(SIGALRM, func);
    
        pid_t id = -1;
    
        id = fork();
        if (id > 0)
        {
            printf("in parent pro
    ");
        }
        else if (id == 0)
        {
            raise(SIGALRM);
        }
    
    
        return 0;
    }

     

    这段代码在子进程可以触发 SIGALRM 信号处理函数

     

     vfork

    和fork比较,

    vfork不会复制父进程的地址空间,共享父进程代码段、数据段等。在子进程调用exec,exit之前,父子进程共享数据段

    父进程会阻塞,直到子进程调用exec或者退出

    vfork适合在子进程直接调用exec族函数。如果调用了其它函数,因为栈共享的原因,会导致父进程段错误

    #include <sys/types.h>
    #include <sys/unistd.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    
    
    int main()
    {
        pid_t id = -1;
    
        id = vfork();
        if (id > 0)
        {
            printf("parent process...
    ");
        }
        else if (id == 0)
        {
            sleep(1);
            execl("/bin/ls", "ls", nullptr);
        }
    
        return 0;
    }

     父子进程共享数据段、堆栈:

    #include <sys/types.h>
    #include <sys/unistd.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <sys/wait.h>
    #include <stdlib.h>
    
    
    int global_a = 20;
    
    int main()
    {
        int local_b = 30;
    
        pid_t id = vfork();
        if (id > 0)
        {
            printf("in parent pro, global_a = %d, local_b = %d
    ", global_a, local_b);
        }
        else if (id == 0)
        {
            global_a++;
            local_b++;
            printf("in child pro, global_a = %d, local_b = %d
    ", global_a, local_b);
            _exit(0);
        }
        else
        {
            perror("vfork");
        }
    
    
        return 0;
    }

    输出:

    in child pro, global_a = 21, local_b = 31
    in parent pro, global_a = 21, local_b = 31

    两个输出结果相同,说明,数据段和栈是共享的

  • 相关阅读:
    RUP十大要素的应用
    使用ASP.NET 3.5 Extensions管理浏览器历史:使用服务器端
    Autodesk云计算系列视频 开篇介绍 Up to the cloud 直上云端
    AIMS 2012 不能登录的问题
    Autodesk Infrastructure Modeler (原Galileo伽利略项目)已经正式发布
    MapGuide开发中使用Fusion Viewer及通过程序开关图层
    MapGuide OpenSource 2.2 安装中的数字签名错误
    MapGuide / Map 3D 开发常用资料链接
    基于MapGuide的在线WebGIS站点再介绍
    Autodesk云计算系列视频 云计算与Civil 3D
  • 原文地址:https://www.cnblogs.com/zuofaqi/p/10284213.html
Copyright © 2011-2022 走看看