Linux的fork函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/okiwilldoit/article/details/79709191

一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。

子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间

假定父进程malloc的指针指向0x12345678, fork 后,子进程中的指针也是指向0x12345678,但是这两个地址都是虚拟内存地址,经过内存地址转换后所对应的 物理地址是不一样的。所以两个进程中的这两个地址相互之间没有任何关系。

父子进程的地址空间是相互独立的!

fork后,这两个虚拟地址实际上指向相同的物理地址(内存页);只有任何一个进程试图修改这个虚拟地址里的内容前,
两个虚拟地址才会指向不同的物理地址,新的物理地址的内容从原物理地址中复制得到,这就是Linux的copy-on-write技术。

fork的返回值比较特殊,在父进程和子进程中返回值不相同,如果创建子进程成功,那么
在父进程中,返回子进程pid,
在子进程中,返回0,
如果出现错误,fork返回一个负值。

举个例子说明:

int ForkWork(int count);

int main(int argc, char const *argv[])
{
    int count = 4;

    ForkWork(count);

    return 0;
}

int ForkWork(int count)
{       
    pid_t pid = 0;

    for (int i = 0; i < count; ++i)
    {
        pid = fork();
        if (pid == 0 || pid < 0)
        {
            break;
        }       
    }

    if (pid < 0)
    {
        perror("fail to fork!\n");
        exit(1);
    }
    else if (pid == 0)
    {   
        int a = 10;
        count = 5;
        printf("child-pid:%u, count=%d, count_ptr:%p, a_ptr:%p\n", getpid(), count, &count, &a);
        exit(0);
    }
    else if(pid > 0)
    {
        count = 3;
        printf("father-pid:%u, count=%d, count_ptr:%p\n", getpid(), count, &count);
        exit(0);
    }

    return 0;
}

打印结果:
father-pid:26313, count=3, count_ptr:0x7fff81741c9c
child-pid:26317, count=5, count_ptr:0x7fff81741c9c, a_ptr:0x7fff81741ca4
child-pid:26315, count=5, count_ptr:0x7fff81741c9c, a_ptr:0x7fff81741ca4
child-pid:26314, count=5, count_ptr:0x7fff81741c9c, a_ptr:0x7fff81741ca4
child-pid:26316, count=5, count_ptr:0x7fff81741c9c, a_ptr:0x7fff81741ca4

可以看出父子进程的变量的指针地址是相同的,但是实际的物理地址不同的,值也不相同。

用pid == 0 || pid < 0的条件判断是否break,是为了让子进程跳出循环,父进程继续执行循环。
因为子进程返回0,可以break;
父进程返回的pid>0,则继续执行循环。

猜你喜欢

转载自blog.csdn.net/okiwilldoit/article/details/79709191