Linux多进程开发1 - 进程概述

一、并行和并发

并行 & 并发:有一个例子可以清晰地解释这二位的区别。如果将处理器(CPU)比作咖啡机,指令比作排队买咖啡的客人,则:

并发是两个队列交替使用同一台咖啡机;并行是两个队列同时使用两台咖啡机

二、进程控制块PCB

虚拟地址空间会通过CPU中的MMU(Memory Management Unit——内存管理单元),把虚拟地址空间中的数据映射到物理内存当中去。

在Linux内核中存在一个名为 PCB(Process Control Block——进程控制块)的东西,为了管理进程,操作系统必须对每个进程所做的事情进行清楚的描述,所以为每个进程分配一个PCB。一个PCB中的内容非常多,但只需要掌握以下几个:

  • 进程id:系统中每个进程有唯一的 id,用pid_t类型表示,其实就是一个非负整数
  • 进程的状态:有就绪、运行、挂起、停止等状态
  • 进程切换时需要保存和恢复的一些CPU寄存器
  • 描述虚拟地址空间的信息
  • 描述控制终端的信息
  • 当前工作目录(Current Working Directory)
  • umask 掩码
  • 文件描述符表,包含很多指向文件结构体的指针
  • 和信号相关的信息
  • 用户 id 和组 id
  • 会话(session)和进程组
  • 进程可以使用的资源上限(Resource Limit)

许多文件描述符以数组的形式形成了一个集合,即文件描述符表。一个文件描述符表中最多可以存放1024个文件描述符,文件描述符的作用就是定位磁盘上的某一个文件。

上图展示了一个完整的文件描述符表当中的内容,前3个是默认打开的文件描述符,它们都对应于了一个文件,即当前的终端(在Linux系统中有一句话“一切皆文件”,所以将终端也抽象为一个文件,而我们的显示器、网卡也都可以被抽象为文件)。

三、进程的状态

进程状态反映进程执行过程的变化,这些状态随着进程的执行和外界条件的变化而转换。在三态模型中,进程状态分为三个基本状态,即就绪态运行态阻塞态。在五态型中,进程分为新建态、就绪态,运行态,阻塞态,终止态。

  • 运行态:进程占有处理器正在运行;
  • 就绪态:进程具备运行条件,等待系统分配处理器以便运行。当进程已分配到除CPU以外的所有必要资源后,只要再获得CPU,便可立即执行。在一个系统中处于就绪状态的进程可能有多个,通常将它们排成一个队列,称为就绪队列;
  • 阻塞态:又称为等待(wait)态或睡眠(sleep)态,指进程不具备运行条件,正在等待某个事件的完成
  • 如何杀死进程呢?

首先使用指令 ps aux 来查看现阶段的全部进程

a:显示终端上的所有进程,包括其他用户的进程
u:显示进程的详细信息
x:显示没有控制终端的进程

kill 和 kill -9 这两个命令在Linux中都有杀死进程的效果,然而两命令的执行过程却大有不同,在程序中如果用错了,可能会造成莫名其妙的现象(*以下内容出自Kill区别)。

kill(不加 -* 默认kill -15)命令

系统会发送一个SIGTERM信号给对应的程序。当程序接收到该signal信号后,将会发生以下事情:

  • 程序立刻停止
  • 当程序释放相应资源后再停止
  • 程序可能仍然继续运行

大部分程序接收到SIGTERM信号后,会先释放自己的资源,然后再停止。但是也有程序可能接收信号后,做一些其他的事情(如果程序正在等待IO,可能就不会立马做出响应),也就是说,SIGTERM有可能是会被阻塞的。

kill -9命令

系统给对应程序发送的信号是SIGKILL,即exit。exit信号不会被系统阻塞,所以kill -9能顺利杀掉进程。

总结:

在使用 kill -9 前,应该先使用 kill 指令,给目标进程一个清理善后工作的机会。如果没有,可能会留下一些不完整的文件或状态,从而影响服务的再次启动。

四、创建子进程

pid_t fork(void); 函数的作用:用于创建子进程。

  • fork函数的返回值:

            fork()的返回值会返回两次,一次是在父进程中,一次是在子进程中。

            在父进程中返回创建的 子进程的ID

            在子进程中返回 0

            如何区分父进程和子进程:通过fork的返回值。

            在父进程中返回-1,表示创建子进程失败,并且设置errno

  • 父子进程之间的关系:

区别

            1.fork()函数的返回值不同

                父进程中: >0 返回的子进程的ID

                子进程中: =0

            2.PCB中的一些数据

                当前的进程的id pid不同

                当前的进程的父进程的id ppid不同

                信号集不同

 共同点

            某些状态下:子进程刚被创建出来,还没有执行任何的写数据的操作

                - 用户区的数据

                - 文件描述符表

  • 父子进程对变量是不是共享的?

实际上,更准确来说,Linux 的 fork() 使用是通过写时拷贝 (copy- on-write) 实现。写时拷贝是一种可以推迟甚至避免拷贝数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只用在需要写入的时候才会复制地址空间,从而使各个进行拥有各自的地址空间。也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享。

注意:fork之后父子进程共享文件,fork产生的子进程与父进程相同的文件文件描述符指向相同的文件表,引用计数增加,共享文件偏移指针

父进程创建子进程代码如下,也可以从运行结果中看到CPU对于不同进程的分片操作

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

int main() {

    int num = 10;

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

    // 判断是父进程还是子进程
    if(pid > 0) {
        printf("pid : %d\n", pid);
        // 如果大于0,返回的是创建的子进程的进程号,当前是父进程
        printf("i am parent process, pid : %d, ppid : %d\n", getpid(), getppid());

        printf("parent num : %d\n", num);
        num += 10;
        printf("parent num += 10 : %d\n", num);


    } else if(pid == 0) {
        // 当前是子进程
        printf("i am child process, pid : %d, ppid : %d\n", getpid(),getppid());
       
        printf("child num : %d\n", num);
        num += 100;
        printf("child num += 100 : %d\n", num);
    }

    // for循环
    for(int i = 0; i < 3; i++) {
        printf("i : %d , pid : %d\n", i , getpid());
        sleep(1);
    }

    return 0;
}

五、GDB多进程调试

GDB默认只能跟踪一个进程,可以在 fork 函数调用之前,通过指令设置 GDB 调试工具跟踪父进程或者是子进程,默认跟踪父进程

设置调试父进程或者子进程:set follow-fork-mode [parent(默认) | child]

设置调试模式:set detach-on-fork [on | off]

默认为 on,表示调试当前进程的时候,其它的进程继续运行;如果为off,调试当前进程的时候,其它进程被 GDB 挂起。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue 窗口内容滚动到底部

onMounted(() > {scrollToBottom() }) // 滚动到底部方法 const scrollToBottom () > {// 获取聊天窗口容器let chatRoom: any document.querySelector(".chat-content");// 滚动到容器底部chatRoom.scrollTop chatRoom.scrollHeight; } 效果 聊天窗口代码…

深入理解数据结构第一弹——二叉树(1)——堆

前言&#xff1a; 在前面我们已经学习了数据结构的基础操作&#xff1a;顺序表和链表及其相关内容&#xff0c;今天我们来学一点有些难度的知识——数据结构中的二叉树&#xff0c;今天我们先来学习二叉树中堆的知识&#xff0c;这部分内容还是非常有意思的&#xff0c;下面我们…

常见的Nginx+Redis+MQ+DB架构设计

三高&#xff0c;复杂的架构 SQRS CAP 缓存&#xff0c;限流 【Redis&#xff0c;缓存】 cache-aside 缓存cache&#xff1a;数据源的副本 store 1. Read/Write Through Pattern 读写穿透模式 redis&#xff1a;放当前在线用户&#xff0c;热点数据

Codeforces Round 937 (Div. 4)(A,B,C,D,E,F,G)

比赛链接 这场简单&#xff08;话说div4好少啊&#xff0c;打了二十多把了就两把div4&#xff09;。D直接暴力就可以&#xff0c;E是暴力&#xff0c;F考察了树的性质&#xff0c;根据性质算数就行了&#xff0c;G是个状压。 A. Stair, Peak, or Neither? 题意&#xff1a; …

Github 2024-03-29 Java开源项目日报 Top9

根据Github Trendings的统计,今日(2024-03-29统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目9JavaGuide - Java 程序员学习和面试指南 创建周期:2118 天开发语言:Java协议类型:Apache License 2.0Star数量:140773 个Fork数量:…

HarmonyOS 应用开发之线程模型

Stage模型下的线程主要有如下三类&#xff1a; 主线程 执行UI绘制。管理主线程的ArkTS引擎实例&#xff0c;使多个UIAbility组件能够运行在其之上。管理其他线程的ArkTS引擎实例&#xff0c;例如使用TaskPool&#xff08;任务池&#xff09;创建任务或取消任务、启动和终止Wor…

【Django学习笔记(二)】CSS语言介绍

CSS语言介绍 前言正文1、CSS 快速了解2、CSS 应用方式2.1 在标签上应用2.2 在head标签中写style标签2.3 写到文件中 3、问题探讨&#xff1a;用Flask框架开发不方便4、选择器4.1 ID选择器4.2 类选择器4.3 标签选择器4.4 属性选择器4.5 后代选择器4.6 注意事项 5、样式5.1 高度和…

Spring Transaction 指定事务管理器问题

一&#xff0c;单个数据源&#xff0c;单个事务管理器与Transactional默认事务管理器名称不一致问题 在平时代码中使用声明性事务时&#xff0c;直接在方法上面加注解即可&#xff0c;如下 Transactional(rollbackFor Exception.class) 并没有指定事务管理器&#xff0c;为…

Flink学习(一)-flink 本地部署

1&#xff0c;安装 jdk 官网推荐 jdk11 版本。我用 17也可以跑起来 2&#xff0c;下载 flink-1.19 的版本并解压 下载 release 1.19.0 并解压。 tar -xzf flink-1.19.0-bin-scala_2.12.tgz cd flink-1.19.0 3&#xff0c;启动 ./bin/start-cluster.sh 4&#xff0c;访问…

主干网络篇 | YOLOv8更换主干网络之EfficientNet

前言:Hello大家好,我是小哥谈。EfficientNet是一种高效的卷积神经网络架构,由Mingxing Tan和Quoc V. Le在2019年提出,其设计思想是在不增加计算复杂度的情况下提高模型的准确性。它引入了一个称为"复合系数"的概念,该系数用于同时缩放网络的深度、宽度和分辨率。…

Web开发-Django学习笔记

客户端如何获取服务端的数据信息&#xff1f; 通常 是 HTTP网络协议&#xff0c;通过网络传输数据信息。 客户端通过HTTP协议发送请求信息给服务端&#xff0c;并从服务端接收响应信息。 Web 前端开发&#xff1a; &#xff08;HTML、CSS、JS&#xff09;文件部署在后端服务…

mysql5.7 源码分析--初始化

集中在sql\mysqld.cc文件的mysqld_main函数中&#xff08;&#xff09;&#xff1a; 主程序入口 在sql\main.cc文件中&#xff1a; int main(int argc, char **argv) {return mysqld_main(arg, argv); } 一、mysql为了跨平台&#xff0c;对win32系统做了单独的初始化&#x…

常见手撕项目C++

常见手撕项目C 设计模式单例模式饿汉模式懒汉模式 策略模式策略接口实现具体的策略&#xff08;虚函数重写&#xff09;定义上下文用户调用 设计模式 单例模式 单例模式是一种常用的软件设计模式&#xff0c;其目的是确保一个类只有一个实例&#xff0c;并提供一个全局访问点来…

Modbus转Profinet网关快速解决PLC插槽数量不够用的烦恼

通过Modbus转Profinet&#xff08;XD-MDPN100&#xff09;网关的应用&#xff0c;不仅可以实现Modbus设备与Profinet网络的平滑对接&#xff0c;还能有效解决PLC插槽限制和Modbus指令轮询等问题&#xff0c;Modbus转Profinet网关&#xff08;XD-MDPN100&#xff09;在解决PLC插…

Linux多进程开发2 - 孤儿、僵尸进程

参考学习&#xff1a;彻底搞懂孤儿/僵尸/守护进程 一、孤儿进程(Orphan Process) 父进程运行结束&#xff0c;但子进程还在运行&#xff0c;这样的子进程就称为孤儿进程每当出现一个孤儿进程的时候&#xff0c;内核就把孤儿进程的父进程设置为 init (即养父)Init 会等待被收养…

阿里云实时计算Flink的产品化思考与实践【下】

摘要&#xff1a;本文整理自阿里云高级产品专家黄鹏程和阿里云技术专家陈婧敏在 FFA 2023 平台建设专场中的分享。内容主要为以下五部分&#xff1a; 阿里云实时计算 Flink 产品化思考 产品化实践 SQL 产品化思考及实践 展望 接上篇&#xff1a;阿里云实时计算Flink的产品…

Centos服务器Open Gauss 部署

近期很多的项目由于信创要求使用一些国产的数据库&#xff0c;比如OpenGauss。OpenGuass是华为高斯DB的开源版&#xff0c;内核还是PostgreSQL&#xff0c;商业版是收费的。这里记录一下是如何安装部署 的。 官方中文文档 官方下载地址 部署要求 操作系统要求 ARM&#xff…

《数据结构学习笔记---第六篇》---栈和队列的实现

目录 1.栈 1.1栈的概念及结构 1.2栈的实现 2.队列 2.1队列的概念及结构 ​2.2队列的实现 3.顺序栈的具体实现 3.1建头文Stack.h” 3.2创建具体接口实现文件Stack.c 3.2.1初始化 3.2.2入栈出栈 3.2.4判空 3.2.5栈的大小 3.2.6销毁栈 3.3主函数的实现 4.链队的具体实现…

iOS UIFont-真香警告之字体管理类

UIFont 系列传送门 第一弹加载本地字体:iOS UIFont-新增第三方字体 第二弹加载线上字体:iOS UIFont-实现三方字体的下载和使用 第三弹搭建字体管理类:iOS UIFont-真香警告之字体管理类 前言 不知道友们是否有过这种经历,项目已经迭代了很多版本,项目中的文件已经上千个了…

钉钉服务端API报错 错误描述: robot 不存在;解决方案:请确认 robotCode 是否正确

problem 调用钉钉服务端API&#xff0c;机器人发送群聊消息&#xff0c;后台返回报错信息: 钉钉服务端API报错 错误描述: robot 不存在&#xff1b;解决方案:请确认 robotCode 是否正确&#xff1b; reason 定位: 登录后台&#xff0c;查看机器人是存在查看机器人调用权限接…