2022-1-15 牛客C++项目——第二章 Linux 多进程开发

一、进程的的退出

问题:为什么使用标准 C 库函数和使用 Linux 的系统函数最后会有两个截然不同的结果呢?

exit()

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(void){
    printf("hello\n");
    printf("world");
    exit(0);
    
    return 0;
}

在这里插入图片描述
C 语言的 IO 函数 printf 是有缓冲区的,先将字符串写入缓冲区当中,\n 换行的时候会刷新缓冲区使得字符串输出。

_exit()

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(void){
    printf("hello\n");
    printf("world");
    _exit(0);
    
    return 0;
}

在这里插入图片描述
在函数结束的时候,缓冲区没有被刷新,world 依然停留在缓冲区当中。

孤儿进程
孤儿进程是什么?
下面的程序是怎样创建出孤儿进程的?
为什么子进程会单独有一个终端?

子进程由父进程创建,如果父进程在子进程终止之前终止,那么子进程便成为了孤儿进程,孤儿进程会被 init 进程接管。

下面的程序让子进程先休眠一秒,父进程先运行完成,子进程被 init 进程所接管。

可执行程序运行在后台,当程序结束的时候,会切换到终端(前台),父进程结束之后被切换到了前台,但是没有想到子进程依然在运行。
(其实就是系统控制权的一个转移的过程)

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
int main(void){

   pid_t pid = fork();

   if(pid > 0){
       printf("i am parent process, pid :%d, ppid : %d\n",getpid(),getppid());
   }
   else if(pid == 0){
       sleep(1);
       printf("i am child process,pid : %d,ppid : %d\n",getpid(),getppid());
   }

   for(int i = 0;i < 5;++i){
       printf("i = %d\n",i);
   }
   return 0;
}

在这里插入图片描述
三、僵尸进程
僵尸进程是什么?
僵尸进程是如何产生的?
如何避免僵尸进程?

僵尸进程 —— 进程无法被回收,仍在内存区当中占有 PCB,会占用 pid。僵尸进程太多,会导致无法创建新的进程,因为缺乏足够的 pid 进行分配。

若子进程在父进程之前结束,且父进程陷入了死循环,子进程会因在内存当中的资源无法被释放掉而成为僵尸进程。

使用 kill -9 + 僵尸进程号无法将僵尸进程杀死。

使得父进程终止可能是一种方法。

但是,并不是在很多的情况下能够使得父进程终止。

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
int main(void){

   pid_t pid = fork();

   if(pid > 0){
       while (1)
       {
           sleep(1);
           printf("i am parent process, pid :%d, ppid : %d\n",getpid(),getppid());
       }
   }
   else if(pid == 0){
       //sleep(1);
       printf("i am child process,pid : %d,ppid : %d\n",getpid(),getppid());
   }

   for(int i = 0;i < 5;++i){
       printf("i = %d\n",i);
   }
   return 0;
}

使用 ps aux 查看进程的状态,发现子进程为僵尸进程。

使用 top 查看进程的实时状态。
在这里插入图片描述

进程回收
为什么要使用 wait 函数?
详细解释 wait 函数的参数和返回值?
什么是传出参数?

下图中的函数一共有几个子进程?为什么?
如何避免这样的事情发生?

4 个。
调用第一个 fork()的时候,出现了第一个子进程。
父进程调用第二个 fork(),再来一个进程。
第一个子进程和父进程共享同一段代码,也会调用第二个 fork(),又来一个进程。所以一共有四个进程。

通过返回值来区分父进程和子进程的。首先对于执行的对象的身份进行判断,如果是子进程,就不许执行。
在这里插入图片描述
如何创建 5 个子进程?

使用循环创建,如果是子进程访问就退出循环。

#include <sys/types.h>
#include <sys/wait.h>
#include<unistd.h>
#include<stdio.h>
int main(void){
    //有一个父进程,要创建五个子进程
    pid_t pid;
    for(int i = 0;i < 5;++i){
        fork();
        //检测是否是子进程,如果是被创建出来的子进程就跳出循环,防止多次调用创建进程的代码。
        if(pid == 0){
            break;
        }
   	}
   	return 0;
}        

在这里插入图片描述
在这里插入图片描述

#include <sys/types.h>
#include <sys/wait.h>
#include<unistd.h>
#include<stdio.h>
int main(void){
    //有一个父进程,要创建五个子进程
    pid_t pid;
    for(int i = 0;i < 5;++i){
        fork();
        //检测是否是子进程,如果是被创建出来的子进程就跳出循环,防止多次调用创建进程的代码。
        if(pid == 0){
            break;
        }
        if(pid > 0){
            while (1)
            {
                printf("oarent,pid = %d\n",getpid());
                sleep(1);
                
            }
        }
        else if(pid == 1){
                printf("child,pid = %d\n",getpid());
        }
    }
    return 0;
}

在此例中,子进程运行结束之后,父进程一直死循环运行,子进程无法被回收成为僵尸进程。
在这里插入图片描述

#include <sys/types.h>
#include <sys/wait.h>
#include<unistd.h>
#include<stdio.h>
int main(void){
    //有一个父进程,要创建五个子进程
    pid_t pid;
    for(int i = 0;i < 5;++i){
        fork();
        //检测是否是子进程,如果是被创建出来的子进程就跳出循环,防止多次调用创建进程的代码。
        if(pid == 0){
            break;
        }
        if(pid > 0){
            while (1)
            {
                printf("oarent,pid = %d\n",getpid());
                wait(NULL);
               printf("child die.");
                sleep(1);
                
            }
        }
        else if(pid == 1){
            while (1)
            {
                printf("child,pid = %d\n",getpid());/* code */
            }
        }
    }
    return 0;
}

在上面这个程序当中,父进程会被 wait()函数阻塞,而子进程死循环,不会成为僵尸进程。当子进程被人为的信号杀死之后,父进程会接着运行。

在这里插入图片描述
在这里插入图片描述
设置子进程正常退出的状态码为0

#include <sys/types.h>
#include <sys/wait.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(void){
    //有一个父进程,要创建五个子进程
    pid_t pid;
    for(int i = 0;i < 5;++i){
        fork();
        //检测是否是子进程,如果是被创建出来的子进程就跳出循环,防止多次调用创建进程的代码。
        if(pid == 0){
            break;
        }
        if(pid > 0){
            while (1)
            {
                printf("oarent,pid = %d\n",getpid());
                //wait(NULL);
                int st;
                int ret = wait(&st);
                if(ret == -1){
                    break;
                }
                if(WIFEXITED(st)){
                    //判断进程是否正常退出
                    printf("退出的状态码:%d\n",WEXITSTATUS(st));
                }
                if(WIFSIGNALED(st)){
                    //判断是否是异常终止,被信号干掉
                    printf("被哪个信号干掉了:%d\n",WTERMSIG(st));
                }

                printf("child die.");
                sleep(1);
                
            }
        }
        else if(pid == 1){
            // while (1)
            // {
                printf("child,pid = %d\n",getpid());/* code */
            // }
            exit(0);
        }
    }
    return 0;
}

在这里插入图片描述

如果将程序当中的 exit(0)改成 exit(1),子进程退出时候得到的状态码为 1
在这里插入图片描述
使用信号量将子进程杀死

#include <sys/types.h>
#include <sys/wait.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(void){
    //有一个父进程,要创建五个子进程
    pid_t pid;
    for(int i = 0;i < 5;++i){
        fork();
        //检测是否是子进程,如果是被创建出来的子进程就跳出循环,防止多次调用创建进程的代码。
        if(pid == 0){
            break;
        }
        if(pid > 0){
            while (1)
            {
                printf("oarent,pid = %d\n",getpid());
                //wait(NULL);
                int st;
                int ret = wait(&st);
                if(ret == -1){
                    break;
                }
                if(WIFEXITED(st)){
                    //判断进程是否正常退出
                    printf("退出的状态码:%d\n",WEXITSTATUS(st));
                }
                if(WIFSIGNALED(st)){
                    //判断是否是异常终止,被信号干掉
                    printf("被哪个信号干掉了:%d\n",WTERMSIG(st));
                }

                printf("child die.");
                sleep(1);
                
            }
        }
        else if(pid == 1){
             while (1)
            {
                printf("child,pid = %d\n",getpid());/* code */
            }
            exit(0);
        }
    }
    return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值