C++linux高并发服务器项目实践 day6

news2024/11/26 20:19:23

C++linux高并发服务器项目实践 day6

  • exec函数族
    • 介绍
    • execl
    • execlp
    • 其他
  • 进程控制
    • 进程退出
    • 孤儿进程
    • 僵尸进程
    • 进程回收
    • wait()函数
    • waitpid()函数

exec函数族

介绍

exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用内部执行一个可执行文件

exec函数族的函数执行成功后不会反悔,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只留下进程ID等一些表面上的信息仍保持原样。只有调用失败了,他们才会返回-1,从源程序的调用点接着往下执行
在这里插入图片描述
前6个都是C库的函数,只有最后一个是Linux的函数
前2个是最常用的

execl

#include <unistd.h>

extern char **environ;

int execl(const char *pathname, const char *arg, …);
参数:

  • path:需要指定的执行的文件的路径或者名称
    a.out(相对路径) /home/Liunx/a.out (绝对路径)
    两者都能使用,但是推荐使用第二个
  • arg:是执行可执行文件所需要的文件列表
    第一个参数一般没有什么作用,为了方便,一般写的是执行的程序的名称
    从第二个参数开始往后,就是程序执行所需要的参数列表
    参数最后需要以NULL结束(哨兵)

返回值:
只要当调用失败时,才会有返回值,返回-1,并且设置errno
如果调用成功,没有返回值

#include <unistd.h>
#include <stdio.h>


int main(){
    //创建一个子进程,在子进程中执行exec函数族中的函数
    pid_t pid = fork();

    if(pid > 0){
        //父进程
        printf("i am parent process,pid : %d\n",getpid());
        sleep(1);
    }else if(pid == 0){
        //子进程
        
        //execl("hello", "hello",NULL);
        execl("/bin/ps","ps","a","u","x",NULL);

        printf("i am child process,pid = %d\n",getpid());
    }

    for(int i = 0;i < 3;i++){
        printf("i = %d,pid = %d\n",i,getpid());
    }

    return 0;
}

execlp

#include <unistd.h>

extern char **environ;

int execl(const char *pathname, const char *arg, …);
int execlp(const char *file, const char *arg, …);
会到环境变量中查找指定的可执行文件,如果找到了就执行,找不到就执行不成功。
参数:

  • file:需要指定的执行的可执行文件的文件名
    a.out ps
  • arg:是执行可执行文件所需要的文件列表
    第一个参数一般没有什么作用,为了方便,一般写的是执行的程序的名称
    从第二个参数开始往后,就是程序执行所需要的参数列表
    参数最后需要以NULL结束(哨兵)

返回值:
只要当调用失败时,才会有返回值,返回-1,并且设置errno
如果调用成功,没有返回值

#include <unistd.h>
#include <stdio.h>


int main(){
    //创建一个子进程,在子进程中执行exec函数族中的函数
    pid_t pid = fork();

    if(pid > 0){
        //父进程
        printf("i am parent process,pid : %d\n",getpid());
        sleep(1);
    }else if(pid == 0){
        //子进程
        
        //execl("hello", "hello",NULL);
        execlp("ps","ps","a","u","x",NULL);

        printf("i am child process,pid = %d\n",getpid());
    }

    for(int i = 0;i < 3;i++){
        printf("i = %d,pid = %d\n",i,getpid());
    }

    return 0;
}

其他

int execlp(const char *file, const char *arg, …);
int execle(const char *pathname, const char *arg, …);
char *envp[] = {“/home/Liunx”,“/home/bbb”,“/home/aaa”};

int execv(const char *pathname, char const argv[]);
argv是需要的参数的一个字符串数组
char
argv[] = {“ps”,“aux”,NULL}

int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);

进程控制

进程退出

#include <stdlib.h>
void exit (int status);

#include <unistd.h>
void _exit(int status);

status参数:是进程退出时的一个状态信息。父进程回收子进程资源的时候可以获得到。
在这里插入图片描述

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main(){

    printf("hello\n");
    printf("world");

    //exit(0);

    _exit(0);

    return 0;
}

如果是exit()函数,则会打印world,而_exit()并不会
因为c库的exit()函数会多做两部事,其中刷新缓冲区就会将缓冲区里没输出的world输出

孤儿进程

  • 父进程运行结束,但子进程还在运行(未运行结束),这样的子进程就称为孤儿进程
  • 每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为init,而init进程会循环wait()它的已经退出的子进程。这样,当一个孤儿进程结束了其生命周期的时候,init进程就出面处理它的一切善后工作
  • 因此孤儿进程并不会有什么危害

这里拿之前的fork()函数相关代码来改

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

    
int main(){

    //创建子进程
    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循环
    for(int i = 0;i < 5;i++){
        printf("i:%d\n",i);
    }

    return 0;
}

在子进程sleep后,父进程早已执行完被释放,这时子进程就变成了孤儿进程,查看它的ppid为1,说明被init接管,且会进入前台,而不是和父进程共享

僵尸进程

  • 每个进程结束之后,都会释放自己地址空间中的用户区数据,内核区的PCB没有办法自己释放掉,需要父进程去释放
  • 进程终止时,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程
  • 僵尸进程不能被kill -9杀死
  • 这样就会导致一个问题,如果父进程不调用wait()或waitpid()的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程,此即为僵尸进程的危害,应当避免

依然是拿那段代码来改,当父进程进入死循环,而子进程就会执行完变成僵尸进程,新开一个命令行窗口,没办法通过kill命令来杀死它
我们可以通过ctrl+c来强行杀死父进程,这样子进程也会消失

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

    
int main(){

    //创建子进程
    pid_t pid = fork();

    //判断是父进程还是子进程
    if(pid > 0){
        while(1){
            printf("i am parent process,pid:%d,ppid:%d\n",getpid(),getppid());
            sleep(1);
        }
    }else if(pid == 0){
        sleep(1);
        //当前是子进程
        printf("i am child process ,pid: %d,ppid :%d\n",getpid(),getppid());
    }

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

    return 0;
}

进程回收

  • 在每个进程退出的时候,内核释放该进程所有的资源、包括打开的文件、占用的内存等。但是仍然为其保留一定的信息,这些信息主要指进程控制块PCB的信息(包括进程号、退出状态、运行时间等).
  • 父进程可以通过调用wait或waitpid得到他的退出状态同时彻底清除掉这个进程
  • wait()和waitpid()函数的功能意义,区别在于,wait()函数会阻塞,waitpid()可以设置不阻塞,waitpid()还可以指定等待哪一个子进程结束
  • 注意:一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环

wait()函数

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
功能:等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收子进程的资源、
参数:int *wstatus
进程退出时的状态信息,传入的是一个int类型的地址,传出参数
返回值:

  • 成功:返回被回收的子进程的ID
  • 失败:返回-1(所有的子进程都结束,调用函数失败)

调用wait函数的进程会被挂起(阻塞),直到它的一个子进程退出或者受到一个不能被忽略的信号时才被唤醒(相当于继续往下执行)
如果没有子进程了,函数立刻返回,返回-1;如果子进程都已经结束了,也会立即返回-1

pid_t waitpid(pid_t pid, int *wstatus, int options);
在这里插入图片描述

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

int main(){

    //有一个父进程,创建5个子进程(兄弟)
    pid_t pid;

    //创建5个子进程
    for(int i = 0; i < 5;i++){
        pid  = fork();

        if(pid == 0){
            break;
        }
    }

    if(pid > 0){
        //父进程
        while ((1))
        {
            printf("parent,pid = %d\n",getpid());

            //int ret = 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 dir,pid = %d\n",ret);

            sleep(1);
        }
        

    }else if(pid == 0){
        //子进程
       // while (1)
       // {
            printf("child,pid = %d\n",getpid());
            sleep(1);
        //}
        
        exit (0);
    }


    return 0;
}

waitpid()函数

#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *wstatus, int options);
功能:回收指定进程号的子进程,可以设置是否阻塞
参数:

  • pid:
    pid > 0:某个子进程的pid
    pid = 0:回收当前进程组的所有子进程
    pid = -1:回收所有的子进程,相当于wait() (最常用)
    pid < -1:某个进程组的组id 的绝对值,回收指定进程组中的子进程
  • options:设置阻塞或者非阻塞
    0:阻塞
    WNOHANG:非阻塞

返回值:
> 0:返回子进程的id
= 0:options = WNOHANG,表示还有子进程活着
= -1:错误,或者没有子进程了

wait(&wstatus) == waitpid(-1,&wstatus,0);

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

int main(){

    //有一个父进程,创建5个子进程(兄弟)
    pid_t pid;

    //创建5个子进程
    for(int i = 0; i < 5;i++){
        pid  = fork();

        if(pid == 0){
            break;
        }
    }

    if(pid > 0){
        //父进程
        while ((1))
        {
            printf("parent,pid = %d\n",getpid());
            sleep(1);

            //int ret = wait(NULL);
            int st;
            //int ret = waitpid(-1,&st,0);
            int ret = waitpid(-1,&st,WNOHANG);

            if(ret == -1){
                break;
            } else if(ret == 0){
                //说明还有子进程存在
                continue;
            }else if(ret > 0){
                if(WIFEXITED(st)){
                    //是不是正常退出
                    printf("退出的状态码:%d\n",WEXITSTATUS(st));
                }
                if(WIFSIGNALED(st)){
                    //是不是异常终止
                    printf("被哪个型号干掉了:%d\n",WTERMSIG(st));

                }
            }

  

            printf("child dir,pid = %d\n",ret);


        }
        

    }else if(pid == 0){
        //子进程
        while (1)
        {
            printf("child,pid = %d\n",getpid());
            sleep(1);
        }
        
        exit (0);
    }


    return 0;
}

子进程和父进程在运行时交替运行,在子进程被逐个kill后,父进程这边会显示被-9型号干掉了,当所有的子进程都被kill了之后,父进程会退出

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/429156.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【路径规划】Dubins路径

简介 在无障碍物的情况下&#xff0c;路径规划中最简单的形式&#xff0c;就是将路径看作是由直线段和常曲率圆弧段组成&#xff0c;这就是Dubins路径。Dubins路径可以简单的理解为&#xff1a;在最大曲率限制下&#xff0c;平面内两个由方向的点间的最短可行路径是 CLC 路径或…

[STM32F103C8T6]基于LCD和DHT11、HC08的温湿度检测系统并上传服务器

项目实际图 本次项目需要整合LCD1602、DHT11、HC08、继电器 1.首先是LCD1602显示程序 封装管脚&#xff0c;这样的话写时序的时候不用随时都在哪儿HAL_GPIO_WritePin #define RS_GPIO_Port GPIOB #define RW_GPIO_Port GPIOB #define EN_GPIO_Port GPIOB #define RS_Pin GPI…

PP模块-生产主数据之一-物料主数据

物料主数据的配置主要在 MM 模块中进行管理&#xff0c;一般由MM顾问或MDM的顾问负责流程梳理、规则讨论、并主导完成数据收集工作。所以在SAP系统项目的实施过程中&#xff0c;根据系统对物料主数据数特有的配置对象要求&#xff0c;与业务负责人进行讨论并达成一致&#xff0…

FreeRTOS如何解决访问冲突/线程不安全(临界段、互斥锁、挂起调度、看门人任务)

在多任务&#xff08;多线程&#xff09;系统中&#xff0c;存在一个隐患&#xff0c;那就是多线程的访问&#xff08;在FreeRTOS中就是任务&#xff09;。当一个任务A开始访问一个资源&#xff08;外设、一块内存等&#xff09;&#xff0c;但是A还没有完成访问&#xff0c;B任…

精通 TensorFlow 2.x 计算机视觉:第二部分

原文&#xff1a;Mastering Computer Vision with TensorFlow 2.x 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的形象&#xff0c;…

【RabbitMQ学习日记】—— 再见RabbitMQ

一、发布确认高级篇 在生产环境中由于一些不明原因&#xff0c;导致 rabbitmq 重启&#xff0c;在 RabbitMQ 重启期间生产者消息投递失败&#xff0c;导致消息丢失&#xff0c;需要手动处理和恢复如何才能进行 RabbitMQ 的消息可靠投递呢&#xff1f; 特别是在这样比较极端的情…

MYSQL:数据类型与运算符、MySQL函数

一.部分需要学会的操作&#xff08;以举例形式列出&#xff09;&#xff1a; insert into tmp15 values(This is good,50); /*向tmp15插入note 为 “This is good”&#xff0c;price为50的元素*/ 注&#xff1a;需要严格对应字段和元素属性的位置 select * from tmp15 /*查…

【Diffusion Model】Learning notes

来自 扩散模型 Diffusion Model 1-1 概述 扩散模型是什么&#xff1f; 本质是生成模型&#xff0c;拟合目标分布&#xff0c;然后生成很多数据符合这个分布 训练测试阶段&#xff1f; 和 GAN 相比优势是什么&#xff1f; generator 和 discriminator 两者都得训练的比较均衡…

JDK8到JDK17有哪些吸引人的新特性?

作者&#xff1a;京东零售 刘一达 前言 2006年之后SUN公司决定将JDK进行开源&#xff0c;从此成立了OpenJDK组织进行JDK代码管理。任何人都可以获取该源码&#xff0c;并通过源码构建一个发行版发布到网络上。但是需要一个组织审核来确保构建的发行版是有效的, 这个组织就是J…

Excel VBA 之Interior 对象设置底色

Interior 对象 代表一个对象的内部 针对interior对象&#xff0c;我们用得最多的是它的颜色&#xff0c;下面就来讨论一下。 1.ColorIndex 索引颜色值 Sub 索引颜色值()For i 1 To 56Cells(i, 1).Interior.ColorIndex iCells(i, 2) iNext iFor i 1 To 56Cells(i, 3).Interi…

算法训练第六十天 | 84.柱状图中最大的矩形

单调栈part0384.柱状图中最大的矩形题目描述思路暴力解法双指针解法单调栈84.柱状图中最大的矩形 题目链接&#xff1a;84.柱状图中最大的矩形 参考&#xff1a;https://programmercarl.com/0084.%E6%9F%B1%E7%8A%B6%E5%9B%BE%E4%B8%AD%E6%9C%80%E5%A4%A7%E7%9A%84%E7%9F%A9%E…

《Kubernetes部署篇:Ubuntu20.04基于containerd二进制部署K8S 1.24.12集群(一主多从)》

一、架构图 如下图所示&#xff1a; 如下图所示&#xff1a; 二、环境信息 1、部署规划 主机名IP地址操作系统内核版本软件说明etcd01192.168.1.62Ubuntu 20.04.5 LTS5.15.0-69-genericetcdetcd02192.168.1.63Ubuntu 20.04.5 LTS5.15.0-69-genericetcdetcd03192.168.1.64Ubunt…

kettle链接mysql Public Key Retrieval is not allowed

kettle 报错信息页面&#xff1a; 出现 Public Key Retrieval 的场景可以概括为在禁用 SSL/TLS 协议传输切当前用户在服务器端没有登录缓存的情况下&#xff0c;客户端没有办法拿到服务器的公钥。具体的场景如下&#xff1a; 新建数据库用户&#xff0c;首次登录&#xff1b;数…

课程推荐 | 机器视觉与边缘计算应用

点击蓝字关注我们,让开发变得更有趣文案 | 李擎排版 | 李擎文案来源 | https://www.icourse163.org/course/FUDAN-1456632162OpenVINO™╱ 前言 ╱机器视觉是目前人工智能重要的应用领域&#xff0c;在很多领域都有丰富的成功应用案例。其中深度学习的目标检测算法是非常实用的…

ubuntu(20.04)-shell脚本(1)-基本概念

目录 1.概述 2.shell脚本调用形式 3.shell语法初识 3.1 定义以开头&#xff1a;#&#xff01;/bin/bash 3.2 单个“#”号代表注释当前行 4.变量 4.1 只读变量 4.2 环境变量&#xff1a; env 4.3 预测变量&#xff1a; 4.4 变量扩展&#xff1a; 是否存在&#xff0c;字符串…

通过JMH框架 测试公平锁与非公平锁的性能(附测试代码和源码分析)

目录 先上测试代码&#xff1a; 上依赖&#xff1a; 输出结果&#xff1a;(注意不要debug运行&#xff0c;直接运行代码&#xff0c;否则报错) 源码-公平锁的 lock 方法&#xff1a; 源码-非公平锁的lock方法&#xff1a; 总结 非公平锁和公平锁的两处不同&#xff1a; …

docker入门之一:docker基础概念与安装

1. Docker简单介绍 1.1. 什么是docker&#xff1f;1.2. Docker和传统虚拟机1.3. 为什么使用docker1.4. docker架构 2. Docker安装 2.1. docker版本命名2.2. docker安装2.3. docker卸载2.4. docker镜像加速器 1. Docker简单介绍 1.1. 什么是docker&#xff1f; google go语言…

24-Tomcat

目录 1.Tomcat是什么&#xff1f; 2.版本号 3.下载 4.目录介绍 4.1.bin目录 4.2.conf目录 4.3.logs目录 4.4.webapps目录 5.启动服务器 PS&#xff1a;解决Tomcat乱码问题 PS&#xff1a;Tomcat点击启动&#xff0c;控制台一闪而过&#xff0c;啥也没有解决方案 PS…

【花雕学AI】4月5日,ChatGPT中国财经背景分析:昨天沪指重返3300点,这说明了什么?

在这里插入图片描述 附录&#xff1a; 一、ChatGPT是一个可以和你聊天的人工智能程序&#xff0c;它可以用文字回答你的问题&#xff0c;也可以根据你的提示写出文章、歌词、代码等内容。ChatGPT是由一个叫OpenAI的机构开发的&#xff0c;它使用了一种叫做GPT的技术&…

TCP协议的相关特性(续)

TCP协议的相关特性&#x1f50e;滑动窗口&#x1f50e;流量控制&#x1f50e;拥塞控制&#x1f50e;延时应答&#x1f50e;捎带应答&#x1f50e;面向字节流(粘包问题)&#x1f50e;异常情况&#x1f50e;总结关于 确认应答 超时重传, 连接管理 请参考: 点击这里 &#x1f50e…