Linux 进程3
进程地址空间
CPU读取数据都需要地址,在计算机中所有东西都是一种数据,包括我们的进程。

这是一个进程空间示意图,操作系统通过task_struct结构体链表来管理每一个进程,结构体里面有一个指针指向操作系统为进程开辟的一段空间,里面就是我们熟悉的栈,堆,静态区,代码段等程序的空间。
这个空间是一段连续的地址,但它不是真实的是一种映射通过页表映射到真实物理内存的一个方便的映射关系。所以其实在真实的物理内存中进程与其数据的存放不一定是连续的,只是通过了页表的映射方式来让进程的空间地址看起来是连续的而已,这个叫做虚拟内存空间。

这一段代码,定义了一个全局的变量val并在子进程中修改为100,子进程在linux中会发生写时拷贝即在修改的时候对其进行拷贝再修改所以我们在打印的时候看到父子进程的val值不同是正常的,但是这里的地址也是相同的。真实内存中一个地址对应一个字节,同一个地址有两个不同的值是不可能的,所以我们可以确定在程序内这个地址用的也是虚拟地址,而其相同是因为子进程将包括页表在内的信息都复制下来了,但是映射的物理内存空间是不同的。就是相同的页表相同的地址但是对应着不同的内存单元所以就发生两个不同的值。
fork函数
平时使用计算机我们可能同时看着视频,开着游戏,然后又在工作,那么这些都是一个程序,但是这些程序却能同时运行,这是一种CPU的并发或者并行处理多个事务的能力。其实不止上面的,就我们打开一个视频APP点开一个视频也是需要下载和播放这两个工作同时发生的,一个APP就可以看作是 一个程序那么这个两个同时发生的事件是不可能在一个进程里的,因为我们的代码都是从上到下依次执行语句的一定会有先后顺序,所以这里介绍一个系统调用函数fork就可以让我们做到一个程序同时执行两个事务。
fork函数是一个系统调用函数,在程序中可以为当前进程创建一个子程序,子程序是继承自当前程序的所有信息。所以上面进程地址空间中的虚拟地址都是相同的。
当我们调用了fork函数之后当前程序会被挂起,跳转到内核程序中(因为fork是一个系统调用函数),当轮到当前进程的时间片的时候,就会在内核中创建一个进程,在linux中就是创建一个进程PCB这个PCB基本上就是复制的父进程的,然后赋予子进程ID。一般创建一个进程系统会给分配一段进程地址空间但是这个是不分配的直接调用父进程的为了节省消耗提升效率,只有我们执行下去将里面的一些数据进行修改的时候系统才会进行数据的拷贝并分配一块新的地址空间给子进程(这是写时拷贝)。若是整个进程结束都没有对数据进行修改,那么这个拷贝就不会发生,父子进程会一直公用一段空间。
fork()的返回值类型为pid_t是一个宏其实就是一个int类型,若是返回的-1表示进程创建失败,若是为0表示当前进程为子进程,若是大于0表示当前进程是父进程。是否很奇怪,我们创建的进程到哪里去了呢,父进程又是怎么去管理呢?
当我们进入fork函数之后就不再在程序内部而是在内核程序中了,这时内核创建了一个进程PCB链接入进程队列中,这时候还没返回到调用fork的进程中但是已经是有两个进程在了,而且两个进程在同一行中返回接收fork的返回值,这时已经是两个并发或者并行运行的进程了,所以接下来的所有代码父子进程都会继续执行。而我们分辨父子进程的方式就是返回值,父进程会返回子进程的PID以方便对子进程进行管理,一般就是接收子进程的退出信息。若是父进程比子进程先结束那么子进程会由父进程的父进程即祖宗进程所继承,我们以命令行启动进程为例就是bash进程会继承子进程称为子进程新的父进程。若是子进程先于父进程结束会给父进程返回一个退出码,父进程读取退出码就能只能子进程是完成任务退出的还是出异常退出的,若是父进程一直没有接收那么子进程就会成为僵尸进程一直占用资源不会释放PCB和地址空间导致内存泄漏。
exit函数
exit用于终止一个进程的函数也是一个系统调用,_exit()是直接进入内核空间执行进程终止的命令。
exit()会先执行用户定义的清理函数,将对应的缓冲区冲刷在进入内核空间执行进程终止的命令。

与return不同的是return需要在主函数中调用才是进程终止,而exit函数则是无论在那里调用都是终止当前进程,用法与return相似。
wait函数
当我们创建了子进程之后一般都需要由父进程等待子进程退出了之后并接收子进程的退出码才退出。不然就会导致孤儿进程或是僵尸进程,孤儿进程还好会由其祖宗进程继承但是出现僵尸进程的话就会导致内存泄漏影响效率,甚至无法创建新进程。
wait函数就是给父进程用于等待子进程退出的函数。
pid_t wait(int* status) 函数的参数是个输出型参数,我们在外部定义一个int型变量将其地址传递过去,此函数会将退出的信息赋给这个地址中。返回值是一个pid,是退出的进程的pid。wait函数是阻塞等待的,当执行到这条语句时会一直阻塞等待一个进程结束。
pid_t waitpid(pid_t pid,int* status, int options),函数的第一个参数是等待的进程pid,若是输入-1的话就是等待任意一个进程与wait函数的效果一样,第二个与wait函数一样,
第三个参数是等待选项即等待的方法:
WNOHANG:如果没有子进程结束,则立即返回,不阻塞。
WUNTRACED:如果子进程进入停止状态,但不是由于接收到信号而停止,则立即返回其状态。
WCONTINUED:如果子进程继续(发送SIGCONT),则返回其状态。
这些参数是宏,若是我们在optins的位置输入0的话就会成为阻塞等待与wait函数一样。输入WNOHANG的话当执行到这条语句但是没有以结束但还没释放的进程就会立即返回0,并不会一直阻塞。输入WUNTRACED则是当有进程停止或者结束可能是接收到sigstop的信号或者等待资源等信号都会返回并返回此进程pid就不是只当进程结束才会返回。WCONTINUED 这个选项其实没什么用只是检测子进程是否被暂停后又被唤醒,若是的话调用WIFCONTINUED(status)会返回一个ture。
status参数

wait函数的参数是一个输出型参数,输出的信息如上图是一个位图形式的,整形的后十六位不使用只用前十六位,若是进程是正常结束的会有一个退出码退出码保存在第9到16位上,若是非正常退出则无退出码信息而是前8位保存终止信号的信息。core dump则是代表的core dump文件,若是进程是异常终止即由终止信号终止的系统可以保存进程的数据会创建一个core dump文件来存放一般都在当前目录下,若是此位为一则是创建了此文件,这叫核心转储。
exec进程程序替换
使用fork创建了一个子进程之后父子进程公用进程代码的,两个都是相同的那么如果我是需要执行一些其他的任务呢,若是将全部任务都放在一份代码中就会十分臃肿这份代码,所以我们需要使用进程程序替换让子进程换成另外一份代码去执行,这就是exec类函数的作用
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
exec函数共有5个不过这五个都是调用的execve函数实现的,execve函数是真正的系统调用,这些都是对execve函数的封装。参数不同就意味这功能会有些许的差异。
l(list) : 表示参数采用列表
v(vector) : 参数用数组
p(path) : 有p自动搜索环境变量PATH
e(env) : 表示自己维护环境变量

这里用execl举例,使用的是列表形式的,第一个参数是替换的进程的路径,第二个是进程名,后面的是选项,最后以NULL结尾。我们可以理解为在命令行中输入的命令,实际上我们的bash程序也是这么实现的。
#include int main()
{ char *const argv[] = {"ps", "-ef", NULL}; char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL}; execl("/bin/ps", "ps", "-ef", NULL); execlp("ps", "ps", "-ef", NULL); // 带p的,可以使用环境变量PATH,无需写全路径execle("ps", "ps", "-ef", NULL, envp); // 带e的,需要自己组装环境变量execv("/bin/ps", argv); execvp("ps", argv); //带p的,可以使用环境变量PATH,无需写全路径execve("/bin/ps", argv, envp); exit(0); }// 带e的,需要自己组装环境变量
相关文章:
Linux 进程3
进程地址空间 CPU读取数据都需要地址,在计算机中所有东西都是一种数据,包括我们的进程。 这是一个进程空间示意图,操作系统通过task_struct结构体链表来管理每一个进程,结构体里面有一个指针指向操作系统为进程开辟的一段空间&am…...
R语言机器学习遥感数据处理与模型空间预测技术及实际项目案例分析
随机森林作为一种集成学习方法,在处理复杂数据分析任务中特别是遥感数据分析中表现出色。通过构建大量的决策树并引入随机性,随机森林在降低模型方差和过拟合风险方面具有显著优势。在训练过程中,使用Bootstrap抽样生成不同的训练集ÿ…...
shell linux cut 切割字符串
shell linux 切割字符串 在Shell脚本中,可以使用内置的cut命令来切割字符串。cut命令主要有三个选项 -c、-f和-d,分别表示按字符、按字段和指定分隔符来切割字符串。 按字符切割: echo "Hello World" | cut -c 1-5 # 输出&#…...
golang学习笔记31——golang 怎么实现枚举
推荐学习文档 golang应用级os框架,欢迎stargolang应用级os框架使用案例,欢迎star案例:基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识,这里有免费的golang学习笔…...
fastadmin本地安装插件提示”请从官网渠道下载插件压缩包(code:2)(code:1)“
这个问题主要是在fastadmin中为了保证安全性,不让你进行本地的一个安装(离线安装) 解决办法就是去把相应的代码注释掉,把相应的权限开启。 具体步骤 1.在后台的application\config.php文件下; 将这个unknownsources的…...
STM32基础学习笔记-Timer定时器面试基础题5
第五章、TIMER 常见问题 1、基本概念:什么是定时器 ?作用 ?分类 ? 2、时基单元 ?组成 ?计数模式 ?溢出条件 ? 溢出时间计算 ? 3、systick原理 ?代码讲解 &…...
CSS06-元素显示模式、单行文字垂直居中
一、什么是元素显示模式 1-1、块级元素 1-2、行内元素 1-3、行内块元素 1-4、小结 二、元素显示模式转换 三、单行文字垂直居中 CSS 没有给我们提供文字垂直居中的代码,这里我们可以使用一个小技巧来实现。 解决方案: 让文字的行高等于盒子的高度,就可…...
【车联网安全】车端网络攻击及检测的框架/模型
参考标准: 《汽车数据安全管理若干规定(试行)》ISO/SAE 21434《道路车辆 网络安全工程》威胁分析和风险评估(TARA)ISO/DIS 24089R155法规的国标转换:《汽车整车信息安全技术要求》(UN R155&…...
58.【C语言】内存函数(memcpy函数)
目录 1.memcpy *简单使用 翻译: *模拟实现 注意事项: *例题 1.memcpy *简单使用 memcpy:memory copy cplusplus的介绍 点我跳转 翻译: 函数 memcpy void * memcpy ( void * destination, const void * source, size_t num ); 复制内存块 直接从source指向的位置复制num…...
rust一些通用编程的概念
rust一些通用编程的概念 官网文档数据类型 - Rust 程序设计语言 中文版 (rustwiki.org) 变量,数据类型,条件判断,循环 变量 rust中变量的可变性是值得注意的 例如: fn main(){let number 1;number 2;println!("the number is {}&quo…...
SpringBoot基础知识
谈一谈你对SpringBoot的理解,它有哪些特性(优点)? SpringBoot用来快速开发Spring应用的一个脚手架,其目的是用来简化新Spring应用的初始搭建以及开发过程。 优点: 简化配置:提供了很多内置的…...
ubuntu配置libtorch CPU版本
配置环境:Ubuntu 20.04Date:2024 / 08 1、下载最新版本的libtorch wget https://download.pytorch.org/libtorch/nightly/cpu/libtorch-shared-with-deps-latest.zip unzip libtorch-shared-with-deps-latest.zip2、创建一个C工程文件夹,目…...
Docker MySql 数据备份、恢复
docker-compose.yaml实例 version: 3.8 services:db:image: mysql:9.0.1environment:MYSQL_ROOT_PASSWORD: 123456MYSQL_DATABASE: dataMYSQL_USER: dataMYSQL_PASSWORD: 123456MYSQL_ROOT_HOST: % 1、备份 docker exec -it <容器名称> /usr/bin/mysqldump -u root -p12…...
django项目添加测试数据的三种方式
文章目录 自定义终端命令Faker添加模拟数据基于终端脚本来完成数据的添加编写python脚本编写shell脚本执行脚本需要权限使用shell命令来完成测试数据的添加 添加测试数据在工作中一共有三种方式: 可以根据django的manage.py指令进行[自定义终端命令]可以采用第三方…...
用Python提取PDF表格到Excel文件
在对PDF中的表格进行再利用时,除了直接将PDF文档转换为Excel文件,我们还可以提取PDF文档中的表格数据并写入Excel工作表。这样做可以避免一些不必要的文本和格式带来的干扰,获得更易于分析和处理的表格数据,并方便进行更多的格式设…...
Java基础|多线程:多线程分页拉取
前言: 通常我们都会遇到分页拉取的需求,比如与第三方系统同步数据,定时拉取全量数据做缓存,下面我们简单介绍下多线程分页写法 需求: 全量同步第三方系统数据,并在全部数据同步完后,统一做缓存…...
Android RecyclerView 实现 GridView ,并实现点击效果及方向位置的显示
效果图 一、引入 implementation com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30 二、使用步骤 1.Adapter public class UnAdapter extends BaseQuickAdapter<UnBean.ResultBean, BaseViewHolder> {private int selectedPosition RecyclerView.NO_POSITIO…...
Centos中dnf和yum区别对比
dnf和yum是两种不同的包管理工具,它们各自具有独特的特点和优势,主要用于在Linux系统上安装、更新和卸载软件包。以下是dnf和yum之间的主要区别: 1. 依赖关系解决 dnf:dnf在处理依赖关系方面表现出更强的能力。它能够更高效地解…...
CVPT: Cross-Attention help Visual Prompt Tuning adapt visual task
论文汇总 当前的问题 图1:在VTAB-1k基准测试上,使用预训练的ViT-B/16模型,VPT和我们的CVPT之间的性能和Flops比较。我们将提示的数量分别设置为1、10、20、50,100,150,200。 如图1所示,当给出大量提示时,VPT显示了性能的显著下降…...
基于双向 LSTM 和 CRF 的序列标注模型
基于双向 LSTM 和 CRF 的序列标注模型 在自然语言处理中,序列标注是一项重要的任务,例如命名实体识别、词性标注等。本文将介绍如何使用 Keras 构建一个基于双向 LSTM 和 CRF 的序列标注模型。 一、引言 序列标注任务要求为输入序列中的每个元素分配一个标签。传统的方法可…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
HubSpot推出与ChatGPT的深度集成引发兴奋与担忧
上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...
springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...
