Linux_进程的创建

之前了解了进程的相关基础知识,现在来了解一下进程的实际应用

1进程创建的一般过程:

    1)给新进程分配一个标识符。内核中分配一个PCB

    2)复制父进程的环境

    3)分配程序.数据.栈等内存资源

    4)复制父进程的地址空间的内容

    5)将进程置成就绪状态,放入就绪队列

2.fork

    1)首先调用fork之前,要加头文件#include <unistd.h>

    2)函数原型 pid_t fork(void)

    3)返回值:子进程返回0,父进程返回子进程id,出错返回-1,创建子进程失败。

    4)fork调用失败原因:系统内有太多进程或者实际用户的进程数超过了限制。

下面验证一下fork()的返回值 


图中箭头和数字代表程序执行步骤

运行结果:


解释一下:程序开始执行,首先进入父进程,在调用fork之前,先输出父进程的id,执行fork后,父子进程会从fork之后的代码来继续执行,继续执行父进程,pid接受fork返回值,父进程返回子进程id,然后进入子进程,pid接收fork返回值,子进程返回0。

注意:

1)父子进程执行先后顺序不确定

2)调用fork以后,父子进程交替运行。

3)如果父进程先死,子进程就变成孤儿进程,孤儿进程会被1号进程收养。

4)如果子进程先死,子进程就会变成僵尸进程(清理僵尸进程,用wait函数)

另一种执行步骤:(fork后先执行子进程)


3.子进程与父进程

    子进程继承父进程:

        地址空间,进程上下文,进程堆栈,内存信息,文件描述符(父进程打开的文件),信号设置,进程调度优先级,当前路径,根路径,控制终端,进程组,资源限制情况...

    子进程不继承父进程:

        1>父进程的锁子进程不继承

        2>父进程id子进程不继承

        3>父进程未决的信号子进程不继承

        4>父进程的闹钟子进程不继承

    子进程与父进程的关系:

        子进程以父进程为模板,首先复制父进程的PCB,并进行简单修改;复制父进程的虚拟地址空间(页表)对应的物理内存会进行写时拷贝。

4.vfork

    1)首先调用vfork之前,要加头文件#include <unistd.h> 和 #include <sys/types.h>

    2)函数原型 pid_t vfork(void)

vfork 与fork的区别

    1)vfork用于创建一个子进程,创建出来的子进程和父进程共用同一块虚拟空间。但fork出来的子进程具有独立的地址空间。

    2)vfork出来的子进程一定会先执行,父进程会挂起,一直挂起到子进程调用了_exit或exec父进程才会继续执行。

实例:

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

 int glob=100;

 int main(void){
        pid_t pid;

        pid = vfork();
        if(pid==-1) perror("fork"),exit(1);
        else if(pid ==0) {//子进程
                sleep(3);
                glob=200;
                printf("child glob %d \n",glob);
                exit(0);
                }
        else { //父进程
                printf("parent glob %d \n",glob);
        }
        return 0;
}

运行结果:


解释一下:子进程先运行,修改了glob变量的值,调用了exit,父进程调度执行,父子进程共用一块虚拟内存,所以glob的值也被更改。

猜你喜欢

转载自blog.csdn.net/warrior_harlan/article/details/80514875