fork编程实战

前言

       #include <unistd.h>

       pid_t fork(void);

由fork创建的新进程被称为子进程。fork函数被调用一次,但返回两次。两次返回的唯一区别是子进程的返回值是0,而父进程的返回值是子进程的进程ID。将子进程ID发回给父进程的理由是:因为一个进程的子进程可以有多哥,并且没有一个函数使一个进程可以获得其所有子进程的进程ID。fork使子进程得到返回值0的理由是:一个进程只会有一个父进程,所以子进程总是可以调用getppid以获得其父进程的进程ID(进程ID 0总是由内核交换进程使用,所以一个进程ID不可能为0)。
子进程和父进程继续执行fork调用之后的指令。子进程是父进程的副本。例如,子进程获得父进程数据空间、堆和栈的副本。注意,这是子进程所拥有的副本。父、子进程并不共享这些存储空间部分。父、子进程共享正文段(代码段)。

问题一:什么是程序,什么是进程,有什么区别?
程序是静态的概念,gcc xxx.c -o pro 磁盘中生成pro文件,叫做程序。
进程是程序的一次运行活动,程序跑起来,系统中就多了一个进程。
问题二: 如何查看系统中有哪些进程?
a.使用ps指令查看,配合grep来查找程序中是否存在某一个进程。(ps -aux|grep xxx)
b.运用top指令,类似windows下的任务管理器
问题三:什么是进程标识符?
每个进程都有一个非负整数标识的唯一ID,叫做pid,类似身份证
pid=0:称为交换进程,作用—进程调度
pid=1:init进程,作用----系统初始化
编程调用getpid函数获取自身的进程标识符,getppid获取父进程的进程标识符。
问题四:什么叫父进程,什么叫子进程?
进程A创建了进程B,那么A叫做父进程,B叫做子进程,父进程是相对的概念,理解为人类中的父子关系。
问题五:C程序的存储空间是如何分配?(重点)

在这里插入图片描述
实列

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
    
    
        pid_t pid;
        pid_t pid2;
        pid_t retpid;

        pid=getpid();
        printf("before fork: pid = %d\n",pid);

        retpid=fork();

        pid2=getpid();
        printf("after fork:pid = %d\n",pid2);

        if(pid==pid2)
        {
    
    
                printf("this is father print,retpid = %d\n",retpid);
        }
        else{
    
    
                printf("this is child print,retpid=%d,child pid= %d\n",retpid,getpid());
        }
        return 0;
}

进程创建发生了什么?

数据段cp,共享代码段

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
    
    
        pid_t pid;
        int data=10;
        printf("father: id=%d\n",getpid());

        pid=fork();


        if(pid>0)
        {
    
    
                printf("this is father print,pid = %d\n",getpid());
        }
        else if(pid==0){
    
    
                printf("this is child print,child pid= %d\n",getpid());

                data=data+100;
        }

        printf("data=%d\n",data);

        return 0;
}

fork创建一个子进程的一般目的

1.一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的-------父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork/,使子进程处理此请求。父进程则继续等待下一个服务请求到达。
2.一个进程要执行不同的程序。这对shell是常见的情况。在这种情况下,子进程返回后立即调用exec。

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
    
    
        pid_t pid;
        int data=10;

        while(1){
    
    

                printf("please input a data\n");
                scanf("%d",&data);
                if(data==1){
    
    
                 pid=fork();

                  if(pid>0)
                  {
    
    

                  }
                  else if(pid==0){
    
    
                        while(1){
    
    
                                printf("do net request,pid=%d\n",getpid());
                                sleep(3);

                                }
                        }
                  }
                  else{
    
    
                		printf("wait, do nothing\n");
                }

        }

        return 0;
}

vfork函数也可以创建进程,与fork的区别
关键区别一:vfork直接使用父进程存储空间,不拷贝。
关键区别二:vforl保证子进程先运行,当子进程调用exit退出后,父进程才执行。

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include <stdlib.h>
int main()
{
    
    
        pid_t pid;
        int cnt=0;

        pid=vfork();


        if(pid>0)
        {
    
    
                while(1){
    
    
                        printf("cnt=%d\n",cnt);
                        printf("this is father print,pid=%d\n",getpid());
                        sleep(1);

                }
        }
        else if(pid==0){
    
    
                while(1){
    
    
                        printf("this is chilid print ,pid=%d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt==3){
    
    
                                exit(0);
                        }
                }
        }
        return 0;
}

进程退出
正常退出:1.main函数调用return 2.进程调用exit(),标准C库 3.进程调用_exit()或者_Exit(),属于系统调用
补充:1.进程最后一个线程返回 2.最后一个线程调用pthread_exit

父进程等待子进程退出

父进程等待子进程退出并收集子进程的退出状态(下一程序),子进程退出状态不被收集,变成僵尸进程(上一程序就是僵尸进程)。

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include <stdlib.h>
int main()
{
    
    
        pid_t pid;
        int cnt=0;
        int status=10;

        pid=fork();

        if(pid>0)
        {
    
    
                wait(&status);
                printf("child quit,child status= %d\n",WEXITSTATUS(status));
                while(1){
    
    
                        printf("cnt=%d\n",cnt);
                        printf("this is father print,pid=%d\n",getpid());
                        sleep(1);
                }
        }
        else if(pid==0){
    
    
                while(1){
    
    
                        printf("this is chilid print ,pid=%d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt==5){
    
    
                                exit(3);
                        }
                }
        }
        return 0;
}

waitpid的用法
wait使调用者阻塞,waitpid第三个参数,可以使调用者不阻塞。注意:此时的子进程是僵尸进程。

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include <stdlib.h>
int main()
{
    
    
        pid_t pid;
        int cnt=0;
        int status=10;

        pid=fork();

        if(pid>0)
        {
    
    
        //      wait(&status);
                waitpid(pid,&status,WNOHANG);
                printf("child quit,child status= %d\n",WEXITSTATUS(status));
                while(1){
    
    
                        printf("cnt=%d\n",cnt);
                        printf("this is father print,pid=%d\n",getpid());
                        sleep(1);
                }
        }
        else if(pid==0){
    
    
                while(1){
    
    
                        printf("this is chilid print ,pid=%d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt==5){
    
    
                                exit(3);
                        }
                }

        }
        return 0;
}

孤儿进程
父进程如果不等带子进程退出,在 子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程。Linux避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程。

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include <stdlib.h>
int main()
{
    
    
        pid_t pid;
        int cnt=0;
        int status=10;

        pid=fork();


        if(pid>0)
        {
    
    
                printf("this is father print,pid=%d\n",getpid());
        }
        else if(pid==0){
    
    

                while(1){
    
    
                        printf("this is chilid print ,pid=%d,my father pid=%d\n",getpid(),getppid());
                        sleep(1);
                        cnt++;
                        if(cnt==5){
    
    
                                exit(3);
                        }
                }

        }
        return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46777053/article/details/108711933
今日推荐