【Linux】进程控制的详细介绍

news2024/9/21 18:54:25

前言
在此之前,我们学过进程的概念,进程的状态,进程地址空间等一系列进程相关的问题。本章我们继续学习进程,我们要来学习一下进程的控制,关于进程等待,等问题。

目录

    • 1.再次认识Fork函数
      • 1.1 fork()之后操作系统做了什么
    • 2.进程终止
      • 2. 1 进程终止的常见方式:
      • 2. 2 进程退出常见操作方法:
    • 3 .进程等待
      • 3.1 进程等待的必要性:
      • 3.2 进程等待的方法
      • 3.3 获取子进程status:
      • 3.4 阻塞等待:
      • 3.5 非阻塞等待:
    • 4.makefile的新增知识点:

1.再次认识Fork函数

在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程

  • fork之前父进程独立执行,fork之后,父子两个执行流分别执行

  • fork之前只有父进程执行

  • fork之后父子进程代码共享

  • 进程具有独立性,代码和数据必须独立的

  • 因为代码只能读取,所以就不会有人写入,更不会发生写实拷贝,所以这是父子进程代码共享的原因。

  • 通常父子代码共享,父子在不写入时,数据也是共享的

  • 当任意一方试图写入,便以写时拷贝的方式各自一份副本

  • fork之后,是否只有fork之后的代码是被父子进程共享的?

fork之后,父子共享所有的代码!只不过子进程只能从这里(fork)开始执行。
fork之后,父子进程谁先运行并不能给答案,是调度器给答案

1.1 fork()之后操作系统做了什么

  • 进程调用fork,当控制转移到内核中的fork代码后,内核做
  • 分配新的内存块和内核数据(task_ struct)结构给子进程
  • 将父进程部分数据结构内容拷贝至子进程
  • 添加子进程到系统进程列表当中
  • fork返回,开始调度器调度
  • 进程 = 内核的进程数据结构 + 进程的代码和数据

创建子进程的内核数据结构(struct task_struct + struct mm_struct + 页表) + 代码继承父进程,数据以写时拷贝的方式,来进行共享或者独立。

fork函数返回值

  • 子进程返回0,
  • 父进程返回的是子进程的pid

写时拷贝

  • 写时拷贝是一种延迟拷贝的策略~
  • 写时拷贝本身就是有OS的内存管理模块完成的!

2.进程终止

进程终止的时候,操作系统做了什么?

1.进程终止的时候,首先会进入Z状态,父进程会去等待它回收子进程的信息,读取退去时的一些信息,然后将进程设置为X状态,这时才真正的退出,释放内核结构,释放曾静进程加载到内存所对应的到吗和数据。
2. 当然要释放进程申请的相关内核数据结构和对应的数据和代码(本质就是释放系统资源)

2. 1 进程终止的常见方式:

  • 正常退出:
    a.代码跑完,结果正确 b.代码跑完,结果不正确
    main函数的返回值意义是什么?
答:return的意义是返回给上一级进程,用来评判该进程执
行结果用的。(main函数崩溃,返回值就没意义了)
  • 异常退出:
    代码没有跑完,程序崩溃了(信号部分coredump,涉及到一点点)

2. 2 进程退出常见操作方法:

  • 正常退出:(可以通过echo $? 查看进程退出码
    1.从main函数 Return返回
    2.调用exit( n)
    3.调用_exit

注意:在函数内部中,使用Return() 代表返回函数调用。
exit在代码任何地方调用,都表示直接终止进程。
main函数的返回值,是进程退出码(strerror())

  • 异常退出
    1.Ctrl+C :信号终止

程序崩溃的时候,退出码没有意义了(异常退出)
在这里插入图片描述

3 .进程等待

3.1 进程等待的必要性:

1.之前讲过,子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏。。
2. 进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。。
3. 最后,父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对,或者是否正常退出。。
4.父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息。。

3.2 进程等待的方法

  • wait方法
 #include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);
返回值:
成功返回被等待进程pid,失败返回-1。
参数:
输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

代码演示:

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

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        //子进程创建成功
        while(1)
        {
            printf("我是子进程, 我正在运行...Pid: %d\n", getpid());
            sleep(1);
        }
    }
    else
    {
        //父进程
    
        //想看到等待成功之后僵尸进程就不见了
        printf("我是父进程:pid:%d, 我准备电脑等待子进程啦\n", getpid());
        sleep(30);
        
        pid_t ret = wait(NULL);

        if(ret < 0)
        {
            printf("等待失败!\n");
        }
        else 
        {
            printf("等待成功: result: %d\n", ret);
        }

        //父进程等20后再退出
        sleep(20);
    }
}
  • wait()的方案可以解决回收子进程Z状态,让子进程进入X

  • waitpid()方法

pid_t waitpid(pid_t pid, int *status, int options);

返回值:
在这里插入图片描述

  • 返回值大于0:等待子进程成功,返回值就是子进程的进程ID pid
  • 返回值小于0:等待失败
  • 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0
  • 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在

参数:
Pid:

  • pid值大于0:是几就代表等待哪一个子进程, 指定等待
  • pid值等于-1:等待任意进程

status:

  • 是一个输出型参数
  • 通过调用 WIFEXITED(status):若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
  • WEXITSTATUS(status):若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)

子进程会将自己的退出信息写入task_ struct~~
子进程一旦死掉,父进程直接把子进程退出码拷贝到自己(通过waitpid传进来的int status参数,父进程就拿到了子进程的退出结果)*

options:

  • 0:阻塞等待
  • WNOHANG:若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。(非阻塞等待)

3.3 获取子进程status:

  • wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
  • 如果传递NULL,表示不关心子进程的退出状态信息.
  • 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程.

status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位)

在这里插入图片描述
次低八位得到子进程的退出码,最低七位是终止信号。

3.4 阻塞等待:

如果子进程还在运行,则父进程会被阻塞等待,直到子进程退出或被终止,才能继续执行下去。

阻塞等待,父进程等的时候,子进程压根没退出的,父进程只能阻塞式的等,只有等到子进程退出之后才能正式拿出来这里的int* status。

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

int main()
{
    pid_t id = fork();

    if(id == 0)
    {
        //子进程创建成功
        while(1)
        {
            printf("我是子进程, 我正在运行...Pid: %d\n", getpid());
            sleep(1);
            int* p = NULL;
            *p = 100;
        }
    }
    else
    {
        //父进程
        int status = 0;
        printf("我是父进程:pid:%d, 我准备电脑等待子进程啦\n", getpid());
        pid_t ret = waitpid(id, &status, 0);
        if(ret > 0)
        {
            //status >> 8 并不影响status的值
            //status >>= 8 才影响status的值
            // printf("wait success, ret : %d, 我所等待子进程的退出码: %d, 退出信号是: %d\n", ret, (status >> 8) & 0xFF, status & 0x7F);
            if(WIFEXITED(status))
            {
                //子进程是正常退出的
                printf("子进程执行完毕,字进程的退出码:%d\n",WEXITSTATUS(status));
            }
            else
            { 
               printf("子进程异常退出:%d\n",WIFEXITED(status));
            }
        }
    }

    return 0;
}

我们只需要对status进行位操作,就能拿到对应的退出码和退出信号。

我们很显然做了一个对空指针的解引用:

我们能看到退出信号是11号信号,我们来看一下11号信号是什么:
在这里插入图片描述
SIGSEGV的全称是Segmentation Violation,即”段错误”。

3.5 非阻塞等待:

与阻塞等待不同的是,非阻塞等待不是子进程不退出就一直在那里等,而是多次调用非阻塞接口轮询检测!

非阻塞等待时,条件不满足会直接就返回,此时用户不会因为调用了waitpid ()
,让自己阻塞住,一旦条件不满足该函数会立刻返回,父进程或者用户可以继续在返回之后空闲时间段内,做自己的事,做一会之后再去调用waitpid(),这种监测方式叫做非阻塞。

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

//非阻塞等待验证
int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        //子进程 
        //死循环跑不完,但是代码出现异常了,进程收到信号,信号终止了子进程,父进程就要知道
        while(1)
        {
            printf("我是子进程,我的PID : %d, 我的PPID : %d\n", getpid(), getppid());

            sleep(3);
        }

        exit(111);
    }
    else if(id > 0)
    {
        //父进程
        //基于非阻塞的轮询等待方案
        
        int status = 0;
        while(1)
        {
            pid_t ret = waitpid(-1, &status, WNOHANG);
            if(ret > 0)
            {   
                printf("等待成功, %d, exit sig: %d, exit code: %d\n", ret, status & 0x007F, (status & 0xFF00) >> 8);
                break;
            }
            else if(ret == 0)
            {           
                //等待成功了,但是子进程没有退出 -- 函数调用成功了,只不过是在非阻塞状态
                printf("子进程好了没,还没,那么父进程就做其他事情...\n");
                sleep(1);
            }
            else 
            {
                //出错了,暂时不处理
            }
        }
    }
    else 
    {
        //do nothing         
    }
    
    return 0;
}
  • 轮训检测:
    在非阻塞等待的时候,子进程还没退出,父进程虽然是在等子进程,但是不是卡住在那里等待,而是可以做其他的事情

补充知识

  • 阻塞的本质是进程阻塞,把进程阻塞是要改进程状态的,R -> S。
  • 把进程的PCB从运行队列放到等待队列,这都是操作系统干的.
  • 把进程的PCB从运行队列放到等待队列,这都是操作系统干的

4.makefile的新增知识点:

在这里插入图片描述
在这里插入图片描述
如果想要生成两个,makefile代码如下:
在这里插入图片描述
尾声
看到这里,相信大家对这个C++有了解了。
如果你感觉这篇博客对你有帮助,不要忘了一键三连哦

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

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

相关文章

什么是 Modbus协议?

一、网络中的协议是指什么&#xff1f; 网络协议是网络通信中至关重要的一部分&#xff0c;它定义了网络中两个或多个设备之间通信的规则、过程和格式。这些规则确保了计算机网络设备能够使用一种通用语言来传输和接收数据&#xff0c;而不管它们的设计、硬件或基础设施如何。…

MySQL-ubuntu环境下安装配置mysql

文章目录 什么是数据库&#xff1f;一、ubuntu环境下安装mysql二、配置mysql配置文件1.先登上root账号2.配置文件的修改show engines \G; mysql和mysqld数据库的基础操作登录mysql创建数据库显示当前数据库使用数据库创建表插入students表数据打印students表数据select * from …

【吊打面试官系列-ZooKeeper面试题】说说客户端注册 Watcher 实现?

大家好&#xff0c;我是锋哥。今天分享关于 【说说客户端注册 Watcher 实现&#xff1f; 】面试题&#xff0c;希望对大家有帮助&#xff1b; 说说客户端注册 Watcher 实现&#xff1f; 1、调用 getData()/getChildren()/exist()三个 API&#xff0c;传入 Watcher 对象 1000道…

数据结构(Java):树二叉树

目录 1、树型结构 1.1 树的概念 1.2 如何判断树与非树 1.3 树的相关概念 1.4 树的表示形式 1.4.1 孩子兄弟表示法 2、二叉树 2.1 二叉树的概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储 2.5 二叉树的遍历 1、树型结构 1.1 树的概念 树型结构是一种非线…

文本分类--NLP-AI(八)

文本分类任务 任务简介1.字符数值化方式1方式2 2.池化&#xff08;pooling&#xff09;3.全连接层4.归一化函数&#xff08;Sigmoid&#xff09;5.总结 从任务抽象新的技术点Embedding层池化层 任务简介 任务介绍&#xff1a; 字符串分类&#xff0c;根据一句话的含妈量&#…

air-conditioning

air-conditioning 空调机安装 实地测量&#xff1a; 测量宽度 测量高度 测试厚度 其他位置测量 根据实际绘图&#xff1a; 改进图&#xff0c;哈哈&#xff0c;让自己满意也让别人满意 1&#xff09;需要考虑安装位置&#xff0c;减少高空放置&#xff0c;放置高空掉落 2&#…

YOLOv5和LPRNet的车牌识别系统

车牌识别系统 YOLOv5和LPRNet的车牌识别系统结合了深度学习技术的先进车牌识别解决方案。该系统整合了YOLOv5目标检测框架和LPRNet文本识别模型 1. YOLOv5目标检测框架 YOLO是一种先进的目标检测算法&#xff0c;以其实时性能和高精度闻名。YOLOv5是在前几代基础上进行优化的…

Mac应用程序清理卸载工具:App Cleaner Uninstaller for Mac 中文版

App Cleaner Pro是一款Mac上非常好用的软件卸载工具&#xff0c;支持应用卸载、Widget卸载、浏览器插件卸载&#xff0c;支持拖拽卸载和列表卸载&#xff0c;能够非常干净的卸载应用&#xff0c;节省你的磁盘空间。App Cleaner Uninstaller Pro是一款深度清理和卸载的工具&…

Postman下载及使用说明

Postman使用说明 Postman是什么&#xff1f; ​ Postman是一款接口对接工具【接口测试工具】 接口&#xff08;前端接口&#xff09;是什么&#xff1f; ​ 前端发送的请求普遍被称为接口 ​ 通常有网页的uri参数格式json/key-value请求方式post/get响应请求的格式json 接…

uboot默认配置过程

uboot默认配置,对于6ull来说,在uboot源码目录下执行:make mx6ull_14x14_evk_defconfig 1、make mx6ull_14x14_evk_defconfig mx6ull_14x14_evk_defconfig文件是在uboot源码configs/目录下面 执行过程分析 HOSTCC:编译一些.c文件 HOSTLD:制作出scripts/kconfig/conf这个…

[数仓]十二、离线数仓(Atlas元数据管理)

第1章 Atlas入门 1.1 Atlas概述 Apache Atlas为组织提供开放式元数据管理和治理功能,用以构建其数据资产目录,对这些资产进行分类和管理,并为数据分析师和数据治理团队,提供围绕这些数据资产的协作功能。 Atlas的具体功能如下: 元数据分类 支持对元数据进行分类管理,例…

【GD32】从零开始学GD32单片机 | WDGT看门狗定时器+独立看门狗和窗口看门狗例程(GD32F470ZGT6)

1. 简介 看门狗从本质上来说也是一个定时器&#xff0c;它是用来监测硬件或软件的故障的&#xff1b;它的工作原理大概就是开启后内部定时器会按照设置的频率更新&#xff0c;在程序运行过程中我们需不断地重装载看门狗&#xff0c;以使它不溢出&#xff1b;如果硬件或软件发生…

2024-07-13 Unity AI状态机2 —— 项目介绍

文章目录 1 项目介绍2 模块介绍2.1 BaseState2.2 ...State2.2.1 PatrolState2.2.2 ChaseState / AttackState / BackState 2.3 StateMachine2.4 Monster 3 其他功能4 类图 项目借鉴 B 站唐老狮 2023年直播内容。 点击前往唐老狮 B 站主页。 1 项目介绍 ​ 本项目使用 Unity 2…

C++基础(一)

目录 1.不同版本的hello word&#xff01; 2.namespace和&#xff1a;&#xff1a;域作用限定符以及using 2.1 namespace 2.2&#xff1a;&#xff1a; 2.3using用于展开域 3.C输入和输出 4.缺省参数 5.重载 6.引用 6.1引用介绍 6.2 引用的特性 注意&#xff1a; 6.4 c…

基于CSS两种菜单创建方式

作者&#xff1a;私语茶馆 1.前言 HTML多种场景下需要菜单的实现&#xff0c;这里提供两种方式&#xff1a; &#xff08;1&#xff09;基于CSS的POPUP式菜单 特征&#xff1a;按需显示POPUP菜单&#xff0c;但布局是浮动的。 &#xff08;2&#xff09;覆盖式弹出菜单。 …

独家揭秘!五大内网穿透神器,访问你的私有服务

本文精心筛选了五款炙手可热的内网穿透工具&#xff0c;它们各怀绝技&#xff0c;无论您是企业用户、独立开发者&#xff0c;还是技术探索者&#xff0c;这篇文章都物有所值&#xff0c;废话不多说&#xff0c;主角们即将上场。 目录 1. 巴比达 - 安全至上的企业护航者 2. 花…

二次改写内容,ai智能写作软件最便捷

对于自媒体创作者&#xff0c;二次改写是获取内容的一个不错的方法&#xff0c;通过二次改写不仅能提高自媒体内容创作的效率问题&#xff0c;而且还解决了创作中因灵感缺失产不出内容的问题&#xff0c;但是二次改写内容也是需要讲究方法的&#xff0c;如果没有好的方法&#…

68种语言说爱你网页源码

浪漫至死不渝&#xff0c;68种语言说爱你网页源码&#xff0c;本地和上传服务器都可以用&#xff0c;无加密。 网页源码&#xff1a;68种语言说爱你单页.zip 下面是HTML代码CSS代码超过七百多行打包成文件了。 <!DOCTYPE html> <html lang"en"><h…

计算机体系结构和指令系统2

1.存储系统的层次结构 有的教材把安装在电脑内部的磁盘成为“辅存”&#xff0c;把U盘、光盘等成为外存&#xff0c;也有的教材把磁盘、U盘、光盘等统称为“辅存”或外存。 主存——辅存&#xff1a;实现虚拟存储系统&#xff0c;解决了主存容量不够&#xff0c;辅存速度不够的…

【密码学】实现消息认证或数字签名的几种方式

消息认证的目的是验证消息的完整性和确认消息的来源。数字签名的目的是不仅验证消息的完整性和来源&#xff0c;还提供了不可否认性。此外&#xff0c;数字签名还可以验证消息的创建时间&#xff0c;防止重放攻击。那么具体有哪些实现的方式呢&#xff1f; 一、仅提供消息认证…