操作系统fork创建子进程

fork创建子进程

#include <unistd.h>
​
pid_t fork(void);
功能:创建一个子进程
返回值:创建失败返回-1
       创建成功会返回两次
       父进程:返回子进程的pid
       子进程:返回0
​
注意:总进程数或者实际拥有pid的进程数量超过了系统的限制,该函数失败

注意:子进程创建出来后,父子进程会同时各自运行代码,因此可以通过分支判断返回值,来让父子进程执行不同的程序代码

#include <stdio.h>
#include <unistd.h>
​
int main(int argc,const char* argv[])
{
    printf("我是进程%u\n",getpid());
​
    pid_t pid = fork();
    if(-1 == pid)
    {
        perror("fork");
        return -1;
    }
​
    if(0 == pid)
    {
        printf("我是子进程%u,我的父进程是%u\n",getpid(),getppid());
        pause();
    }
    else
    {
        printf("我是父进程%u,我的子进程是%u\n",getpid(),pid);
        pause();
    }
}  
父子进程谁先运行:
  • 通过fork系统调用创建出来的子进程与它父进程会各自往下运行,但是其先后顺序不确定,可以通过睡眠等系统调用确定让哪个进程先执行

子进程是父进程的副本:
  • 由fork创建的子进程会获得拷贝出父进程的data段、bss段、heap段、stack段、I/O流缓冲区。

#include <stdlib.h>         
​
int main(int argc,const char* argv[])
{
    int num = 0;
    int* p = malloc(4);
​
    if(fork())
    {
        sleep(1);
        //  父进程
        num = 1000;
        *p = 1000;
    }
    else
    {
        //  子进程
        num = 2000;
        *p = 2000;
    }
//  各自的num都没有被其他进程改变,证明父子进程的num不是同一个,是子进程拷贝了父进程的数据
    //  虽然父子进程中的num 和p的地址是相同的,但是每个进程都拿到4g的虚拟内存,但是映射的物理内存是不一样的,所以虚拟地址相同没有参考价值
    printf("pid=%u : num=%d *p=%d &num=%p p=%p\n",
            getpid(),num,*p,&num,p);
    sleep(2);
    printf("pid=%u : num=%d *p=%d &num=%p p=%p\n",
            getpid(),num,*p,&num,p);
}
​
#include <stdio.h>                                                          
#include <unistd.h>
​
int main(int argc,const char* argv[])
{
    //  *会残留在输出缓冲区,被拷贝给子进程
    //  子进程创建后会继续代码,有可能也会创建子进程
    printf("*");
    
    for(int i=0; i<3; i++)
    {   
        fork();
    }
}
​
子进程会共享父进程的代码段、文件描述符fd:
  • 通过fork创建的子进程会共享父进程的代码段,fork之前的代码只有父进程执行,fork之后的代码父子进程都有机会执行,主要受到逻辑的控制进入不同的分支

  • 不同的程序之间,文件描述符是不能共享的

  • 但是由fork创建的父子进程之间,是把父进程内核中的文件描述符的表格拷贝给了子进程,此时两者共享父进程的已打开的文件描述符

fork子进程会继承父进程的信号处理方式:
  • 通过fork创建子进程会继承父进程的信号处理方式,是因为子进程共享了父进程的代码段

#include <signal.h>
​
void sigint(int num)
{
    printf("我是进程%u,获得了%d信号\n",getpid(),num);
}
​
int main(int argc,const char* argv[])
{
    signal(SIGINT,sigint);
​
    if(fork())
    {
        printf("我是父进程%u\n",getpid());
        for(;;);
    }
    else
    {
        printf("我是子进程%u\n",getpid());
        for(;;);
    }
}

练习1:实现出孤儿进程与僵尸进程,根据ppid和ps命令查看

#include <stdio.h>
#include <unistd.h>
​
int main(int argc,const char* argv[])
{
    pid_t pid = fork();
    if(pid)
    {
        for(;;)
        {
            printf("我是父进程%u,我的子进程是%u\n",getpid(),pid);
            sleep(1);
        }
    }
    else
    {
        printf("我是子进程%u,\n",getpid());
        sleep(3);
        printf("我私了!\n");
    }                                                                                                                                                                                                   
    /*  孤儿进程
    if(fork())
    {
        printf("我是父进程%u\n");
        sleep(3);
        printf("我是父进程我要死了\n");
    }
    else
    {
        for(;;)
        {
            printf("我是子进程%u,我的父进程是%u\n",
                    getpid(),getppid());
            sleep(1);
        }
    }
    */
}

练习2:给主进程创建出4个子进程,再给每个子进程创建2个子进程

#include <stdio.h>
#include <unistd.h>
​
int main(int argc,const char* argv[])
{
    printf("我是主进程%u\n",getpid());
​
    for(int i=0; i<4; i++)
    {
        if(0 == fork())
        {
            printf("我是进程%u,我的父进程%u\n",getpid(),getppid());
            for(int i=0; i<2; i++)
            {
                if(0 == fork())
                {
                    printf("我是孙子进程%u,我的父进程%u\n",
                            getpid(),getppid());
                    pause();
                }
            }
            pause();
        }
    }
    pause();
}  
  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值