【Linux系统编程】23.孤儿进程、僵尸进程、wait、waitpid

news2024/11/23 4:06:35

目录

孤儿进程

测试代码1

测试结果

僵尸进程

测试代码2

测试结果

wait

参数*wstatus

返回值

测试代码3

测试结果

测试代码4

测试结果

测试代码5

测试结果

waitpid

参数pid

参数*wstatus

参数options

返回值

测试代码6

测试结果

测试代码7

测试结果

测试代码8

测试结果

测试代码9

测试结果

测试代码10

测试结果

孤儿进程

        父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程,称为init进程领养孤儿进程。

测试代码1

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

int main(int argc, char *argv[])
{
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    pid_t jin_cheng = fork();
    if (jin_cheng < 0)
    {
        perror("创建进程错误!");
        exit(1);
    }
    else if (jin_cheng == 0)
    {
        while(1){
            printf("这是子进程,当前进程的ID是%d,父进程ID是%d。\n", getpid(),getppid());
            sleep(1);
        }
    }
    else if (jin_cheng > 0)
    {
        sleep(3);
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d。\n", getpid(),jin_cheng);
        printf("父程序结束!\n");
        printf("孤儿进程产生!\n");
    }
    return 0;
}

测试结果

查看进程的对应父进程。

ps ajx

 

 父进程死后,由1319进程进行收养。

 

僵尸进程

        进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸进程。 僵尸进程不能使用kill命令清除掉的。因为kill命令只是用来终止进程的, 而僵尸进程已经终止。

测试代码2

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

int main(int argc, char *argv[])
{
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    pid_t jin_cheng = fork();
    if (jin_cheng < 0)
    {
        perror("创建进程错误!");
        exit(1);
    }
    else if (jin_cheng == 0)
    {
        sleep(3);
        printf("这是子进程,当前进程的ID是%d,父进程ID是%d。\n", getpid(), getppid());
        printf("子进程结束!\n");
        printf("僵尸进程产生!\n");
    }
    else if (jin_cheng > 0)
    {
        while (1)
        {
            printf("这是父进程,当前进程的ID是%d,子进程ID是%d。\n", getpid(), jin_cheng);
            sleep(1);
        }
    }
    return 0;
}

测试结果

 6138进程已死亡,成为僵尸进程,等待父进程进行回收。

 想要除掉僵尸进程,可以杀掉父进程。

kill -9 6137

 

wait

        一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。

        父进程调用wait函数可以回收子进程终止信息。该函数有三个功能:

  1. 阻塞等待子进程退出,就相当于等待子进程死亡。

  2. 回收子进程残留资源。

  3. 获取子进程结束状态(退出原因)。

        当进程终止时,操作系统的隐式回收机制会:

  1. 关闭所有文件描述符。

  2. 释放用户空间分配的内存。

        内核的PCB仍存在,其中保存该进程的退出状态。可使用wait函数传出参数status来保存进程的退出状态。借助宏函数来进一步判断进程终止的具体原因。

 进程正常结束

WIFEXITED(status)!=0

 获取进程退出状态 (exit的参数),可以在进程正常结束的情况下使用。

WEXITSTATUS(status)

 进程异常终止

WIFSIGNALED(status)!=0

 获取使进程终止信号的编号,可以在进程异常终止的情况下使用。

WTERMSIG(status)

 进程处于暂停状态

WIFSTOPPED(status)!=0

 获取使进程暂停信号的编号,可以在进程暂停的情况下使用。

WSTOPSIG(status)

 进程暂停后已经继续运行

WIFCONTINUED(status)!=0

 父进程牛逼,不关心子进程死亡原因,参数传NULL。

ZiJinCheng_ID = wait(NULL);
man 2 wait

参数*wstatus

传出参数,回收进程的状态。

返回值

成功:清理掉的子进程ID。

失败:-1,没有子进程。

测试代码3

使用wait回收进程。

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

int main(int argc, char *argv[])
{
    int i, wstatus;
    pid_t ZiJinCheng_ID; //子进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    pid_t jin_cheng = fork();
    if (jin_cheng < 0)
    {
        perror("创建进程错误!");
        exit(1);
    }
    else if (jin_cheng == 0)
    {
        for (i = 0; i < 3; i++)
        {
            printf("这是子进程,当前进程的ID是%d,父进程ID是%d,延时%d秒。\n", getpid(), getppid(), i + 1);
            sleep(1);
        }
        printf("子进程结束!\n");
        printf("僵尸进程产生!\n");
    }
    else if (jin_cheng > 0)
    {
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d,父进程开始等待收尸!\n", getpid(), jin_cheng);
        ZiJinCheng_ID = wait(&wstatus);
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d,父进程收尸完成,僵尸进程ID是%d。\n", getpid(), jin_cheng, ZiJinCheng_ID);
        printf("父程序结束!\n");
    }
    return 0;
}

测试结果

测试代码4

查看子进程正常终止情况。

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

int main(int argc, char *argv[])
{
    int i, wstatus;
    pid_t ZiJinCheng_ID; //子进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    pid_t jin_cheng = fork();
    if (jin_cheng < 0)
    {
        perror("创建进程错误!");
        exit(1);
    }
    else if (jin_cheng == 0)
    {
        for (i = 0; i < 3; i++)
        {
            printf("这是子进程,当前进程的ID是%d,父进程ID是%d,延时%d秒。\n", getpid(), getppid(), i + 1);
            sleep(1);
        }
        printf("子进程结束!\n");
        printf("僵尸进程产生!\n");
        return 100;
    }
    else if (jin_cheng > 0)
    {
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d,父进程开始等待收尸!\n", getpid(), jin_cheng);
        ZiJinCheng_ID = wait(&wstatus); //子进程未结束,父进程阻塞在这个函数上
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d,父进程收尸完成,僵尸进程ID是%d。\n", getpid(), jin_cheng, ZiJinCheng_ID);
        if (WIFEXITED(wstatus)) //判断子进程是否正常结束
        {
            printf("子进程正常死亡,死亡原因:%d。\n", WEXITSTATUS(wstatus));
        }
        if (WIFSIGNALED(wstatus)) //判断子进程是否异常结束
        {
            printf("子进程被杀,终止信号是%d。\n", WTERMSIG(wstatus));
        }
        printf("父程序结束!\n");
    }
    return 0;
}

测试结果

测试代码5

查看子进程异常终止情况。

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

int main(int argc, char *argv[])
{
    int i, wstatus;
    pid_t ZiJinCheng_ID; //子进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    pid_t jin_cheng = fork();
    if (jin_cheng < 0)
    {
        perror("创建进程错误!");
        exit(1);
    }
    else if (jin_cheng == 0)
    {
        while(1)
        {
            printf("这是子进程,当前进程的ID是%d,父进程ID是%d,我是长生不老的。\n", getpid(), getppid());
            sleep(1);
        }
    }
    else if (jin_cheng > 0)
    {
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d,父进程开始等待收尸!\n", getpid(), jin_cheng);
        ZiJinCheng_ID = wait(&wstatus); //子进程未结束,父进程阻塞在这个函数上
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d,父进程收尸完成,僵尸进程ID是%d。\n", getpid(), jin_cheng, ZiJinCheng_ID);
        if (WIFEXITED(wstatus)) //判断子进程是否正常结束
        {
            printf("子进程正常死亡,死亡原因:%d。\n", WEXITSTATUS(wstatus));
        }
        if (WIFSIGNALED(wstatus)) //判断子进程是否异常结束
        {
            printf("子进程被杀,终止信号是%d,还说是长生不老,直接把你给杀了。\n", WTERMSIG(wstatus));
        }
        printf("父程序结束!\n");
    }
    return 0;
}

测试结果

waitpid

指定某一个进程进行回收。

man 2 waitpid

 

参数pid

大于0:指定回收子进程的ID。

0:回收和当前调用waitpid一个组的所有子进程。

-1:回收任意一个子进程。

小于-1:回收指定进程组内的任意子进程。

参数*wstatus

传出参数,回收进程的状态。

参数options

WNOHANG:指定回收方式为非阻塞。

0:阻塞回收,功能等于wait函数。

返回值

大于0:成功回收子进程的PID。

0:函数调用时,参数options指定了WNOHANG,并且子进程没有结束。

-1:失败。

测试代码6

以不阻塞的方式回收指定的一个进程。父进程不延时,子进程没有结束,返回0。

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

int main(int argc, char *argv[])
{
    int i;
    pid_t temp_ZiJinCheng_ID;  //临时子进程ID
    pid_t JinCheng_ID;         //子进程ID
    pid_t HuiShou_JinCheng_ID; //回收进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    printf("开始创建进程!\n");
    for (i = 0; i < 5; i++)
    {
        temp_ZiJinCheng_ID = fork();
        if (temp_ZiJinCheng_ID == 0) //子进程,不参与创建进程
        {
            break;
        }
        if (i == 2)
        {
            JinCheng_ID = temp_ZiJinCheng_ID;
        }
    }
    if (i == 5)
    {
        HuiShou_JinCheng_ID=waitpid(JinCheng_ID,NULL,WNOHANG);//以非阻塞的方式回收一个进程ID,JinChen_ID
        if(HuiShou_JinCheng_ID<0){
            perror("回收进程错误");
            exit(1);
        }
        printf("这是父进程,当前进程的ID是%d,回收的子进程是%d。\n", getpid(),HuiShou_JinCheng_ID);
    }
    else
    {
        sleep(i); //延时i秒,按顺序输出
        printf("这是第%d个子进程,当前进程的ID是%d。\n", i + 1, getpid());
    }
    return 0;
}

测试结果

测试代码7

以不阻塞的方式回收指定的一个进程。父进程延时,子进程结束,返回回收的进程ID。

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

int main(int argc, char *argv[])
{
    int i;
    pid_t temp_ZiJinCheng_ID;  //临时子进程ID
    pid_t JinCheng_ID;         //子进程ID
    pid_t HuiShou_JinCheng_ID; //回收进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    printf("开始创建进程!\n");
    for (i = 0; i < 5; i++)
    {
        temp_ZiJinCheng_ID = fork();
        if (temp_ZiJinCheng_ID == 0) //子进程,不参与创建进程
        {
            break;
        }
        if (i == 2)
        {
            JinCheng_ID = temp_ZiJinCheng_ID;
        }
    }
    if (i == 5)
    {
        sleep(5); //延时,最后输出父进程
        HuiShou_JinCheng_ID = waitpid(JinCheng_ID, NULL, WNOHANG); //以非阻塞的方式回收一个进程ID,JinChen_ID
        if (HuiShou_JinCheng_ID < 0)
        {
            perror("回收进程错误");
            exit(1);
        }
        printf("这是父进程,当前进程的ID是%d,回收的子进程是%d。\n", getpid(), HuiShou_JinCheng_ID);
    }
    else
    {
        sleep(i); //延时i秒,按顺序输出
        printf("这是第%d个子进程,当前进程的ID是%d。\n", i + 1, getpid());
    }
    return 0;
}

测试结果

测试代码8

回收一个任意子进程。

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

int main(int argc, char *argv[])
{
    int i;
    pid_t temp_ZiJinCheng_ID;  //临时子进程ID
    pid_t HuiShou_JinCheng_ID; //回收进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    printf("开始创建进程!\n");
    for (i = 0; i < 5; i++)
    {
        temp_ZiJinCheng_ID = fork();
        if (temp_ZiJinCheng_ID == 0) //子进程,不参与创建进程
        {
            break;
        }
    }
    if (i == 5)
    {
        sleep(6);	//延时,确保所有子进程都已经结束,最后输出父进程
        HuiShou_JinCheng_ID = waitpid(-1, NULL, WNOHANG); //以非阻塞的方式回收任意一个子进程ID
        if (HuiShou_JinCheng_ID < 0)
        {
            perror("回收进程错误");
            exit(1);
        }
        printf("这是父进程,当前进程的ID是%d,回收的子进程是%d。\n", getpid(), HuiShou_JinCheng_ID);
    }
    else
    {
        sleep(i); //延时i秒,按顺序输出
        printf("这是第%d个子进程,当前进程的ID是%d。\n", i + 1, getpid());
    }
    return 0;
}

测试结果

        网上教程说是回收任意一个子进程,但是从结果来看,每次都是回收第一个结束的子进程,不排除较新版本的Ubuntu系统优化了回收进程的算法,实现先结束先回收的情况。

 

测试代码9

以阻塞的方式回收全部死亡的子进程。

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

int main(int argc, char *argv[])
{
    int i;
    pid_t temp_ZiJinCheng_ID;  //临时子进程ID
    pid_t HuiShou_JinCheng_ID; //回收进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    printf("开始创建进程!\n");
    for (i = 0; i < 5; i++)
    {
        temp_ZiJinCheng_ID = fork();
        if (temp_ZiJinCheng_ID == 0) //子进程,不参与创建进程
        {
            break;
        }
    }
    if (i == 5)
    {
        while ((HuiShou_JinCheng_ID = waitpid(-1, NULL, 0)) != -1) //以阻塞的方式回收任意一个子进程ID
        {
            printf("这是父进程,当前进程的ID是%d,回收的子进程是%d。\n", getpid(), HuiShou_JinCheng_ID);
        }
        if (HuiShou_JinCheng_ID < 0)
        {
            perror("这是父进程,回收子进程完成,父进程结束!\n");
        }
    }
    else
    {
        sleep(i); //延时i秒,按顺序输出
        printf("这是第%d个子进程,当前进程的ID是%d。\n", i + 1, getpid());
    }
    return 0;
}

测试结果

测试代码10

以非阻塞的方式回收全部死亡的子进程。

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

int main(int argc, char *argv[])
{
    int i;
    pid_t temp_ZiJinCheng_ID;  //临时子进程ID
    pid_t HuiShou_JinCheng_ID; //回收进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    printf("开始创建进程!\n");
    for (i = 0; i < 5; i++)
    {
        temp_ZiJinCheng_ID = fork();
        if (temp_ZiJinCheng_ID == 0) //子进程,不参与创建进程
        {
            break;
        }
    }
    if (i == 5)
    {
        sleep(6);                                                  //延时,确保所有的子进程都死亡
        while ((HuiShou_JinCheng_ID = waitpid(-1, NULL, WNOHANG)) != -1) //以非阻塞的方式回收任意一个子进程ID
        {
            printf("这是父进程,当前进程的ID是%d,回收的子进程是%d。\n", getpid(), HuiShou_JinCheng_ID);
        }
        if (HuiShou_JinCheng_ID < 0)
        {
            perror("这是父进程,回收子进程完成,父进程结束!\n");
        }
    }
    else
    {
        sleep(i); //延时i秒,按顺序输出
        printf("这是第%d个子进程,当前进程的ID是%d,该进程结束。\n", i + 1, getpid());
    }
    return 0;
}

测试结果

 

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

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

相关文章

Zemax2019中文设置

做软件教程啥时候都不能少了切换中文版啊~ 正常打开软件&#xff1a; 点击setup 中的preference 弹出窗口&#xff1a; 选择general 在language的下拉窗口中选择&#xff0c;中文 效果&#xff1a;

实验篇——亚细胞定位

实验篇——亚细胞定位 文章目录 前言一、亚细胞定位的在线网站1. UniProt2. WoLFPSORT3. BUSCA4. TargetP-2.0 二、代码实现1. 基于UniProt&#xff08;不会&#xff09;2. 基于WoLFPSORT后续&#xff08;已完善&#xff0c;有关代码放置于[python爬虫学习&#xff08;一&#…

[保研/考研机试] 杨辉三角形 西北工业大学复试上机题 C++实现

题目描述 Time Limit: 1000 ms Memory Limit: 256 mb 输入n值&#xff0c;使用递归函数&#xff0c;求杨辉三角形中各个位置上的值。 输入描述: 一个大于等于2的整型数n 输出描述: 题目可能有多组不同的测试数据&#xff0c;对于每组输入数据&#xff0c; 按题目的要求输…

Java笔记-kafka

修改kafka的server.properties配置 概念 单播 一个消费组的消费者们只有一个能消费到消息。类似queue队列。 多播 不同的消费组的消费者能重复消费到消息&#xff0c;类似publish-subscribe模式 消费组偏移 kafka和别的消息中间件不一样&#xff0c;不同组可以重复消费&a…

Grafana监控 Redis Cluster

Grafana监控 Redis Cluster 主要是使用grafana来实现监控&#xff0c;grafana可以对接多种数据源&#xff0c;在官网中可以找到Redis数据源&#xff0c;需要安装redis data source插件。当然也可以利用Prometheus来做数据源&#xff0c;下面分别记录一下这两种数据源的安装配置…

前后端分离------后端创建笔记(04)前后端对接

本文章转载于【SpringBootVue】全网最简单但实用的前后端分离项目实战笔记 - 前端_大菜007的博客-CSDN博客 仅用于学习和讨论&#xff0c;如有侵权请联系 源码&#xff1a;https://gitee.com/green_vegetables/x-admin-project.git 素材&#xff1a;https://pan.baidu.com/s/…

“MongoDB基础知识【超详细】

"探索MongoDB的无边之境&#xff1a;沉浸式数据库之旅" 欢迎来到MongoDB的精彩世界&#xff01;在这个博客中&#xff0c;我们将带您进入一个充满创新和无限潜力的数据库领域。无论您是开发者、数据工程师还是技术爱好者&#xff0c;MongoDB都将为您带来一场令人心动…

网络安全威胁与防御策略

第一章&#xff1a;引言 随着数字化时代的快速发展&#xff0c;网络已经成为人们生活和工作中不可或缺的一部分。然而&#xff0c;网络的广泛应用也引发了一系列严峻的网络安全威胁。恶意软件、网络攻击、数据泄露等问题层出不穷&#xff0c;给个人和企业带来了巨大的风险。本文…

UI美工设计岗位的基本职责概述(合集)

UI美工设计岗位的基本职责概述1 1、有良好的美术功底、设计新颖&#xff0c;整体配色及设计创意理念&#xff0c;能够独立完成整个网站页面设计及制作; 2、熟练运用DIV CSS&#xff0c;HTML 设计制作网页 ; 3、熟练运用Photoshop,Dreamweaver,Coreldraw(或Illustrator),Fla…

7-2 计算物体自由下落的距离

一个物体从100米的高空自由落下。编写程序&#xff0c;求它在前3秒内下落的垂直距离。设重力加速度为10米/秒2。 输入格式: 本题目没有输入。 输出格式: 按照下列格式输出 height 垂直距离值结果保留2位小数。 代码长度限制 16 KB 时间限制 400 ms 内存限制 64 MB …

异常(下)Java常见异常,异常的使用原则

文章目录 前言一、Java常见异常 1.常见异常2.实例展示二、异常的使用原则总结 前言 该文介绍了Java的一些常见异常&#xff0c;并给出对应的例子进行解释。介绍异常的使用原则&#xff0c;即创建&#xff0c;抛出异常的编程规范。 一、Java常见异常 前要&#xff1a;Java API中…

实训五:用户和组账号管理

实训五&#xff1a;用户和组账号管理 2017 年 X 月 X 日 今日公布 四&#xff1a;实训内容 用root用户登录系统&#xff0c;查看用户账号文件/etc/passwd和口令文件/etc/shadow的内容&#xff0c;注意观察其存储格式、各账户所使用的Shell、UID、GID等属性信息。 答&#xf…

ITIL4—度量和报告实践

1. 关于本文 本文为度量和报告实践提供了实用指南&#xff0c;分为五个主要部分&#xff0c;涵盖&#xff1a; 本实践的基本信息本实践相关的流程和活动&#xff0c;及其在服务价值链中的作用参与本实践的组织和人员支持本实践的信息和技术合作伙伴和供应商在本实践中的注意事…

【构造】CF1853D

Problem - D - Codeforces 题意&#xff1a; 思路&#xff1a; Code&#xff1a; #include <bits/stdc.h>using i64 long long;const int N 1e6 10;int ans[N];void solve() {int n;std::cin >> n;std::vector<std::pair<int,int> > a(n 1);for …

如何高效进行项目任务管理?掌握这些神器助你一臂之力

任务管理是项目管理中的重点部分&#xff0c;关系到项目能否顺利的完成。项目经理该如何进行项目任务管理呢&#xff1f; 一、项目任务管理中的挑战 二、项目任务管理指南 三、项目任务管理神器 首先我们需要先清楚当下企业在项目任务管理中遇到的挑战。 一、项目任务管理中的…

【Kafka】2.在SpringBoot中使用官方原生java版Kafka客户端

目 录 1. 新建一个消息生产者2. 新建一个消息消费者3. 测 试 在开始之前&#xff0c;需要先做点准备工作&#xff0c;用 IDEA 新建一个 Maven 项目&#xff0c;取名 kafka-study&#xff0c;然后删掉它的 src 目录&#xff0c;接着在 pom.xml 里面引入下面的依赖。这个项目的作…

HCIP学习--BGP3

目录 前置内容 BGP下一跳的修改问题 BGP的属性 配置 PrefVal权重属性 负载分担 LocPrf 负载分担 NextHop AS-PATH Ogn 配置 MED 配置 BGP选路规则 BGP的社团属性 配置及解释 前置内容 HCIP学习--BGP1_板栗妖怪的博客-CSDN博客 HCIP学习--BGP2_板栗妖怪的博客…

Python 解析c文件并导出到Excel

文章目录 1. 目录结构&#xff1a;2.代码1. test.c2. write_excel.py3. cparser.py4. 模板.xlsx5. output.xlsx 脚本中主要使用 openpyxl cparser 库 1. 目录结构&#xff1a; ast.txt &#xff1a;存放解析 c 文件的语法树&#xff0c;便于查找内容cparser.py &#xff1a;解…

@Param详解

文章目录 背景什么是ParamParam的使用方法使用方法&#xff1a;遇到的问题及因Param解决了什么问题使用与不使用对比 Param是如何进行映射的总结 背景 最近在开发过程中&#xff0c;在写mapper接口是在参数前加了Param注解&#xff0c;但是在运行的时候就会报错&#xff0c;说…

Elasticsearch 8.X 复杂分词搞不定,怎么办?

1、实战问题 球友提问&#xff1a;我想停用所有纯数字的分词 &#xff0c; 官网上的这个方法好像对ik分词器无效&#xff01; 有没有什么别的方法啊&#xff0c; chart gpt 说分词可以用正则匹配 但是测试好像是不行的 我的es版本是 8.5.3。 2、进一步沟通后&#xff0c;得…