当前位置: 首页 > article >正文

[Linux]进程控制详解

1.创建进程

在这里插入图片描述
进程调用fork,当控制转移到内核中的fork代码后,内核做:
● 分配新的内存块和内核数据结构给子进程
● 将父进程部分数据结构内容拷贝至子进程
● 添加子进程到系统进程列表当中
● fork返回,开始调度器调度

这个前面提到过,就不多说了

2.写时拷贝

引言:当程序变成二进制后,所有的变量名都会变成地址。
fork之后代码共享,就是子进程被创建时,会以父进程为模板,子进程和父进程默认拥有一份相同的代码和数据,当然页表中存储的地址也是一样的。
在这里插入图片描述
在这里插入图片描述
两个问题:
创建子进程时,为什么不直接把父进程的数据给一份?
因为操作系统按需分配,节省空间。

为什么要拷贝?开新空间就好了啊
这里的写:包括了增删查改,不是全被都被覆盖。可能只修改一部分的数据

上图中页表部分括号里有个只读权限,接下来我们分析一下页表

(i)页表

页表不仅仅有虚拟地址和物理地址,物理地址还包括了权限
在这里插入图片描述
举例:字符常量无法被修改,就是我们在写入时,由虚拟地址到物理地址的转化中,权限中没有写入权限。
写代码时const的意义:把运行时产生的错误提前到编译时(防御性编程)

3.终止进程

进程退出情况

我们写代码时,最后都会return 0,main函数的返回值,就是进程的退出码
一般0表示成功,非0表示失败。
在进程执行结束之后,如果进程失败了,我们最想知道的是他的错误原因

echo $?
这个可以查看进程的退出码

当然错误码我们是无法理解的,所以就有错误码转化为错误描述
strerror()
在这里插入图片描述
我们可以看看linux中的错误码

int main()
{
    for(int i=0;i<200;i++)
    {
        printf("%d: %s\n",i,strerror(i));
    }
    return 0;
}

在这里插入图片描述

函数退出情况

除了进程有退出,函数也是有退出的。
函数也是有返回值的,函数的返回值就是错误码,这个和进程的一样
在这里插入图片描述

总结

总结:
任何进程的最终执行情况我们用两个数字表示==(异常)信号编号+进程退出码

如何让进程退出?
1.main函数return
2.exit(退出码)——终止进程,status(进程退出码)
这个进程退出码status会在进程等待中详细的说

4.进程等待

我们提到的父进程如果不等待子进程,就会使子进程变成僵尸进程,会引发内存泄漏
在这里插入图片描述
所以父进程通过wait的方式去回收子进程的资源,这个是必须要做的事情。
在这里插入图片描述
wait会默认进行阻塞等待,等待任意一个子进程;
返回值大于0,等待成功,等待子进程的pid;返回值小于0,等待失败

int main()
{

    pid_t id = fork();
    if (id == 0)
    {
        // child
        int cnt = 5;
        while (cnt)
        {
            printf("I am child,pid: %d,ppid: %d\n", getpid(), getppid());
            cnt--;
            sleep(1);
        }
        printf("马上变僵尸\n");
        exit(0);
    }
    sleep(10);
    // father
    pid_t rid = wait(NULL);
    if (rid > 0)
    {
        printf("wait success child_id:%d\n", rid);
    }
    return 0;
}

在这里插入图片描述
wait比较简单,我们来看看waitpid()
在这里插入图片描述
status:局部使用的位图形式在这里插入图片描述
在这里插入图片描述
status的8到15位时退出码,0到7时退出信号。

提取status的信号:status&0x7F
这样就把他的前7位的数字取出来了;
提取status的退出码:(status>>8)&0xFF
这样就把他的次低8位的数字取出来了.
当然这种方式太麻烦了,我们有专门的宏来完成这件事
在这里插入图片描述

if (WIFEXITED(status))
    {
        printf("wait success,rid: %d,status: %d,exit code: %d\n",rid,status,WEXITSTATUS(status));
    }

非阻塞等待才是重点
在这里插入图片描述
这里当options设位0,就是阻塞等待,设为WNOHANG就是非阻塞等待。
非阻塞:当在等待子进程退出的时候,父进程还可以去做别的事情

waitpid的返回值:
● 大于0:系统调用成功
● 等于0:系统调用成功,但子进程还没退出
● 小于0:调用失败

我们用代码来看看非阻塞等待的优势

const static int NUM=3;
typedef void(*func_t)();

func_t task[NUM];


void printfNAME()
{
    printf("this is print name\n");
}
void printfNPC()
{
    printf("this is print npc\n");
}
void printfAGE()
{
    printf("this is print age\n");
}

void InitLog()
{
    task[0]=printfNAME;
    task[1]=printfNPC;
    task[2]=printfAGE;
    task[3]=NULL;
}
void Exe()
{
    for(int i=0;task[i];i++)
    {
        task[i]();
    }
}
int main()
{
    InitLog();
    pid_t id = fork();
    if (id == 0)
    {
        // child
        int cnt = 5;
        while (cnt)
        {
            printf("I am child,pid: %d,ppid: %d\n", getpid(), getppid());
            cnt--;
            sleep(1);
        }
        sleep(12);
        exit(111);
    }
    // father
    int status=0;
    pid_t rid = waitpid(id,&status,WNOHANG);
    while(1)
    {
        if(rid>0)
        {
            printf("wait sucess,rid: %d,status: %d,exit code: %d\n",rid,status,WEXITSTATUS(status));
            break;
        }
        else if(rid==0)
        {
            printf("child is running,do other thing\n");
            //开始任务
            printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
            Exe();
        }
        else
        {
            perror("waitpid");
            break;
        }
        sleep(1);
    }

    return 0;
}

当子进程还在运行的时候,父进程不是傻傻的等,等待的时候可以去完成别的工作。


http://www.kler.cn/news/310172.html

相关文章:

  • 【LeetCode】2332. 坐上公交的最晚时间
  • AI驱动TDSQL-C Serverless 数据库技术实战营-ai学生选课系统数据分析
  • 基于Java+SpringMVC+vue+element宠物管理系统设计实现
  • Python安装虚拟环境Conda
  • Nacos未授权访问
  • 情感计算领域可以投稿的期刊与会议
  • C++ | Leetcode C++题解之第415题字符串相加
  • .NET 框架版本年表
  • ChatGPT对话训练数据采集渠道有哪些
  • JavaScript 的 DOM 技术
  • 如何划分 PostgreSQL 数据库权限
  • BOE(京东方)领先科技赋能体育产业全面向新 以击剑、电竞、健身三大应用场景诠释未来健康运动新生活
  • AI之所以会具有巨大的作用,体现在它对于产业的深度影响和改造上
  • FEAD:fNIRS-EEG情感数据库(视频刺激)
  • 83.static关键字
  • 《Effective C++》第三版——构造、析构、赋值运算
  • 视频美颜SDK与直播美颜工具的实现原理与优化方案
  • JS 常见的排序算法及比较
  • 进程优先级和环境变量
  • 【算法】BFS系列之 FloodFill 算法
  • 算法:TopK问题
  • IMS中的号码规整 5G注册流程中的语音相关参数
  • Java | Leetcode Java题解之第414题第三大的数
  • LEETCODE 每日一题 (单调栈 +滑动窗口模拟)
  • 【H2O2|全栈】关于CSS(6)CSS基础(五)
  • 达梦disql支持上翻历史命令-安装rlwrap
  • 在家找不到手机?除了语音助手,还可以用远程控制!
  • MySQL查询第M条到第N条数据(M<N)
  • Ubuntu20.04点击文件闪退
  • STM32 - 笔记4