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

Linux进程控制

进程控制

  • fork函数
  • 进程终止
    • 退出码
    • 常见的退出方式
  • 进程等待
    • 什么是进程等待,为什么要进程等待
    • 阻塞与非阻塞
  • 进程替换
    • 替换原理
    • 替换函数
      • 执行系统命令
      • 执行自己写的程序
  • 模拟实现简易的shell

fork函数

fork函数是创建一个子进程,之前用过。

#include <unistd.h>
pid_t fork(void);

返回值:自进程中返回0,父进程返回子进程id,出错返回-1。
进程拥有独立性,fork之后就变成了两个程序,父子进程共享后边的代码。
那么为什么给父进程返回的就是子进程的pid,而给子进程返回的就是0呢?
就好比孩子只能有一个亲生的父亲,而一个父亲可以拥有很多亲生孩子,每个孩子都是独立不同的。
fork函数是在什么时候创建的子进程呢?

pid_t fork()
{1.创建PCB2.赋值3.创建进程地址空间4.赋值5.创建并设置页表6.子进程放入进程队列//这里才是创建成功一个进程,也是分流的地方7.........return pid;//返回的时候核心代码已经执行完毕了
}

也就是说fork返回两个值是因为返回之前就已经创建好新进程了。
返回的本质就是写入,谁先返回谁先写入id,因为进程的独立性,然后就会发生写时拷贝。
fork失败的原因
系统拥有太多个进程超过了用户进程的限制就会失败。

进程终止

退出码

在写C/C++的时候,我们在main函数是程序的开始,但是最后一个位置会写return 0;
这也就代表一个程序的退出,至于为什么要写return 0,而不是返回其他的,亦或者是不写都可以,因为返回uid这个数字是退出码,0是正常退出的意思,因为正确只有一个,不会管你怎么成功,但是失败就会找失败的原因再去改正。
在这里插入图片描述
在这里插入图片描述
echo $?是查看最近进程的退出码,上一个写的进程退出码是1,再查一次就是echo $?的退出码,是0.
退出码可以自定义,也可以使用系统的映射关系,这里不太推荐。
在这里插入图片描述
这个之前用过:
然后来看看里面数字对应的错误信息
在这里插入图片描述
在这里插入图片描述
注意:如果程序异常退出码也无意义。

常见的退出方式

上面说了在mian函数中调用return就是进程退出。
C语言和操作系统还提供了两个函数退出进程:
在这里插入图片描述
这是C语言提供的一个函数,只要使用就会退出当前进程,参数是退出码。
在这里插入图片描述
在这里插入图片描述
无论是在哪个位置,或者是后面有多少代码。
还有一个系统级别调用的是_exit,作用几乎相同:
在这里插入图片描述
在这里插入图片描述
系统调用的并没有打印。
在这里插入图片描述
在这里插入图片描述
这是C语言提供的,过了两秒钟就打印出来了。
这说明:
exit 终止进程后会主动刷新缓冲区。
_exit 终止之后不会主动刷新缓冲区。
那么这个缓冲区在哪里呢?
在这里插入图片描述
exit会刷新缓冲区,但是系统不会,也就是说位置在系统调用和库函数之间,具体的以后说。

进程等待

什么是进程等待,为什么要进程等待

之前说过僵尸进程会导致内存泄漏,因为他的资源无法回收,所以就需要等待子进程结束然后来保存资源给父进程,通过获取子进程退出信息知道是否成功退出。
首先来看两个等待进程的函数。
wait/waitpid:
在这里插入图片描述
status参数是拿该进程的退出结果。
options参数是传入阻塞和非阻塞状态。
pid_t是返回进程的pid,返回-1代表失败。
wait
在这里插入图片描述
这个程序10-15秒是僵尸进程,15s之后就会被回收,这个时候子进程就不是僵尸状态了。
waitpid
在举例之前首先说一下status:
一个程序终止有三种情况,代码运行完毕,结果正确和不正确,还有没运行完,出异常了。
这个时候status是获取他们这个信息的,并且它是拥有自己的位图结构的。
一共有32个比特位,其中重要的只有16个比特位:
在这里插入图片描述
终止信号是一个进程出异常了会受到终止信号,暂时用来判断进程是否正常退出。
退出状态是看结果是否正确。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这个是等待的过程,其实就是status去PCB找信号和退出码。
总结来说:status让操作系统释放掉僵尸状态,然后获取进程的退出结果。
但是如果让我们自己去求信号和退出码很麻烦,所以Linux提供了一些操作的宏,重点说两个:

WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)

所以就可以改良成这个样子:
在这里插入图片描述
在这里插入图片描述
结论:
进程退出会变成僵尸,之后将自己的推出结果放入PCB,wait/waitpid是系统调用,有资格去读取PCB中的资源。

阻塞与非阻塞

阻塞
父进程一直在等子进程结束回收资源。
非阻塞
父进程一段时间过来看一下子进程是否结束,如果没结束可以做其他事情,这个叫轮询方式。
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
NO1就父进程是不是询问子进程是否退出。
如果在询问之后不子进程没有准备完毕,父进程则可以做一些其他的事情。
至于非阻塞和阻塞谁更好,这个要看实际场景。

进程替换

之前说过创建子进程的目的是让子进程去帮忙“做事”,可是为什么要去让子进程帮忙做事呢?
首先说目的:
1.想让子进程执行父进程磁盘代码其中的一部分。
2.想让子进程执行一个全新的程序。

替换原理

在这里插入图片描述
一个可执行程序被首先被加载到内存中,然后执行代码,然后代码中有操作让本程序执行一个新程序,这个时候就会将指定执行的程序的代码和数据覆盖掉原本的代码和数据,在整个过程中并没有产生新的进程,这就是为什么每次都要去创建一个子进程来去执行新程序。

替换函数

执行系统命令

在这里插入图片描述
这些函数的作用是将指定的程序加载到内存当中,让指定的进程执行。
int execl(const char *path, const char *arg, …);
第一个参数是说如何找到程序,第二个参数是我们在命令行解释器怎么调用该程序就怎么写,最后用NULL结尾。
这几个函数统一的是exec,这个函数最后一个l 意思是 list 将参数一个一个传入exec*
在这里插入图片描述
这里执行完execl之后,后边打印process就不会执行,因为整个程序的代码和数据已经被覆盖掉了。
在这里插入图片描述
并且这类函数返回值只有-1,表示错误。
因为成功之后接下来的代码是不会执行的,所以返回一个正确的值进行判断也毫无意义。
int execlp(const char *file, const char *arg, …);
结尾是p的第一个参数不用去指定路径了,他会在环境变量PATH,进行可执行程序的查找
在这里插入图片描述
在这里插入图片描述
int execv(const char *path, const char *argv[], …);
v是vector的意思,第二个参数是让我们把所有可执行参数放入数组中传过去。
在这里插入图片描述
在这里插入图片描述
int execvp(const char *file, const char *argv[], …);
这个就不演示了,这两个参数上面都说过。
上面的只是在执行系统命令,那么想执行自己写的程序该怎么办呢?

执行自己写的程序

首先来说一下makefile这个文件:
先创建一个.c文件
在这里插入图片描述
如果我想让test.c去调用process.c,首先要生成这两个可执行程序,但是makefile只会默认的生成第一个可执行程序,后面的就不会再去执行,所以我们要这样写:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
因为是调用程序,所以不管是什么语言的程序都可调用。
int execle(const char *path, const char *arg, …,char *const envp[]);
最后一个参数是自定义环境变量的意思。
在这里插入图片描述
在这里插入图片描述
现在的自定义环境变量还没定义,所以为空。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们发现,如果没有自定义环境变量,系统自带的环境变量就会被打印,但是如果自定义环境变量系统自带的环境变量就不会被打印。
那么如果我两个都想要怎么办呢?
在这里插入图片描述
这个函数传入你的自定义环境变量就可以了,作用就是将你定义的环境变量导入到系统当中。
在这里插入图片描述
在这里插入图片描述
这里穿插一个问题,一个程序运行之前,是先调用main还是先调用exec函数呢?
是先调用exec函数,因为它的作用上面说了,是将程序加载到内存中,Linux中,它就是加载器。
调用exec函数之后会将自己的参数等等传给main函数,这就是为什么之前说main函数有三个参数,谁传给他的。
int execvpe(const char *file, const char *argv[], …,char *const envp[]);
这个参数就不说了,都说过了。
注意:上面这些接口都是execve系统调用,其他的都是封装,为了让我们有更好的选择性。

模拟实现简易的shell

首先来利用main函数的参数来实现一个功能:
在这里插入图片描述
在这里插入图片描述
那么我们可有利用这个模拟实现一个简单的shell。
第一步先设置输入和输出,并且创建一个字符数组储存输入的参数。
在这里插入图片描述
我们输入一个字符串是abc,然后会按回车,也就是说实际上是abc\n,如果我要在打印信息%s后面加一个\n那么就会多出一行,不加容易出现缓冲区不刷新问题,所以我们要去除输入末尾的\n。
在这里插入图片描述
第二步要进行字符串分割,因为我们在屏幕输入的是ls -a -l这种,但是exec函数要用到的是字符指针数组类型的,所以我们创建一个字符指针数组,然后进行分割放进字符指针数组:
在这里插入图片描述
这里要说一下内建命令,我们在输入ls什么的时候不同文件会有颜色,但是如果调用exec里面就需要自己添加颜色选项,我们又不能在屏幕输入,所以只能在代码中添加,首先判断一定要是ls命令才行,然后添加颜色选项。
像这种不需要让子进程来执行,而是shell自己执行的就叫做内建命令。
第三步是打印,创建一个子进程帮我们工作,这是因为exec函数会替换掉原来程序中所有的代码和数据:
在这里插入图片描述
然后我们还可以设置一个条件编译来看看字符指针数组中的字符切割是否正确:
在这里插入图片描述
先来测试一下上面的程序是否正确
在这里插入图片描述
但是如果我们输入cd …就会发现根本没有任何变化,这是为什么呢?
在这里插入图片描述
先创建一个其他程序来看一下一个进程的状态:
用ls /proc/pid -al
在这里插入图片描述
cwd是当前进程的工作目录,也是我们平时说的当前路径,exe是当前程序执行的是磁盘路径的哪一个程序。
那么这个当前路径可以改变嘛?通过一个函数是可以的:
在这里插入图片描述
谁调用这个函数就更改谁的工作目录,参数是更改到哪个目录。
如果更改了工作目录,那么以后这个程序再进行创建文件等等操作,就会再新的工作目录创建,因为系统默认是跟可执行程序同一个目录下去创建新文件。
那么刚才我们的shell不能cd …是因为他只能让当前工作目录发生变化,因为shell是通过创建子进程去执行命令,我们让目录进行变化的时候是让子进程去帮助执行,也就是说改变的其实是子进程的目录,和父进程没有任何关系,所以说这里还需要创建一个内建命令:
在这里插入图片描述
在这里插入图片描述
之有前还有一个命令,是echo $?,返回的是最近一次退出码
在这里插入图片描述
首先创建两个全局变量保存退出码和信号,然后再用他们储存子进程返回的结果:
在这里插入图片描述
最后进行判断:
在这里插入图片描述
这里简单的完善一下就可以了,主要是综合了上面所说的大部分内容。
在这里插入图片描述

相关文章:

Linux进程控制

进程控制fork函数进程终止退出码常见的退出方式进程等待什么是进程等待&#xff0c;为什么要进程等待阻塞与非阻塞进程替换替换原理替换函数执行系统命令执行自己写的程序模拟实现简易的shellfork函数 fork函数是创建一个子进程&#xff0c;之前用过。 #include <unistd.h…...

PMP项目管理引论介绍

目录1. 指南概述和目的1.1 项目管理标准1.2 道德与专业行为规范2 基本要素2.1 项目2.2 项目管理的重要性2.3 项目、项目集、项目组合以及运营管理之间的关系2.3.1 概述2.3.2. 项目组合与项目集管理2.3.3. 运营管理2.3.4. 组织级项目管理和战略2.3.5. 项目管理2.3.6. 运营管理与…...

计算机视觉废钢堆提取问题

计算机视觉废钢堆提取问题 背景介绍 在钢铁炼制中&#xff0c;废钢是非常重要的原料&#xff0c;不同等级废钢对于钢成品影响很大&#xff0c;因此需要对废钢进行正确分类。某废钢料场中&#xff0c;卸料区域布置了多个摄像头&#xff0c;用于拍摄卸料场中废钢堆&#xff0c;…...

判断水仙花数-课后程序(Python程序开发案例教程-黑马程序员编著-第二章-课后作业)

实例5&#xff1a;判断水仙花数 水仙花数是一个3位数&#xff0c;它的每位数字的3次幂之和等于它本身&#xff0c;例如13 53 33 153&#xff0c;153就是一个水仙花数。 本实例要求编写程序&#xff0c;实现判断用户输入的3位数是否为水仙花数的功能。 实例目标 掌握Pytho…...

目标检测: 数据增强代码详解

1. 常见的数据增强 1.1 翻转图像 左右水平翻转 假设图片的宽高为w,h,bdbox左上角A坐标为(x1,y1), 右下角B为(x2,y2)。经过左右水平翻转后,bdbox的左上角A1坐标(w-x2,y1) ,右下角B1坐标为(w-x1,y2)左右水平翻转的代码实现如下:from PIL import Image image = Image.open(i…...

第二讲:ambari编译复盘,如何实现一次性成功编译ambari

上节课我们已经讲解了如何成功编译ambari源码,安装ambari-server rpm包以及成功部署ambari。本节课我们来复盘一下上节课的编译过程,以及思考如何实现一次性成功编译ambari。 要想一次性成功编译ambari,那么就需要将预置工作做好,比如: maven镜像源配置,node_moudle模块…...

Windows下jdk安装与卸载-超详细的图文教程

jdk安装 下载jdk 由于现在主流就是jdk1.8&#xff0c;所以这里就下载jdk1.8进行演示。官方下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads/#java8-windows。 官方下载需要注册oracle账号&#xff0c;国内下载有可能速度慢&#xff0c;若不想注册账…...

Jackson CVE-2018-5968 反序列化漏洞

0x00 前言 同CVE-2017-15095一样&#xff0c;是CVE-2017-7525黑名单绕过的漏洞&#xff0c;主要还是看一下绕过的调用链利用方式。 可以先看&#xff1a; Jackson 反序列化漏洞原理 或者直接看总结也可以&#xff1a; Jackson总结 影响版本&#xff1a;至2.8.11和2.9.x至…...

解析MySQL 8.0 OCP(1Z0-908)考试中一道大部分同学都会做错的题目

一个用户有下面的权限: mysql>SHOW GRANTS FOR jsmith;---------------------------------------------------------------------- | Grants for jsmith% | ----------------------------------------------------------…...

Java死锁

什么是死锁&#xff1f; 多个线程同时被阻塞&#xff0c;它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞&#xff0c;因此程序不可能正常终止。 死锁的必要条件&#xff1a; 1、互斥条件&#xff1a;该资源任意一个时刻只由一个线程占用。 2、请求与…...

BloomFilter原理学习

文章目录BloomFilter简单介绍BloomFilter中的数学知识fpp(误判率/假阳性)的计算k的最小值公式总结编程语言实现golang的实现[已知n, p求m和k](https://github.com/bits-and-blooms/bloom/blob/master/bloom.go#L133)参考BloomFilter简单介绍 BloomFilter我们可能经常听到也在使…...

C语言老题新解第1-5题

文章目录1 互不相同且无重复数字2 企业利润提成3 两个完全平方数4 判断一年的第几天5 三个整数比较大小1 互不相同且无重复数字 1 有1, 2, 3, 4四个数字&#xff0c;能组成多少互不相同且无重复数字的三位数&#xff1f;都是多少&#xff1f; 最简单当然是三重循环嵌套在一起…...

【数据库系列】MQSQL历史数据分区

互联网行业企业都倾向于mysql数据库&#xff0c;虽说mysql单表能支持亿级别的数据量&#xff0c;加上索引优化下查询速度&#xff0c;勉强能使用&#xff0c;但是对于追求性能和效率的互联网企业&#xff0c;这是远远不够的。Mysql数据库单表数据量到达500万左右&#xff0c;达…...

MyBatis常用的俩种分页方式

1、使用 limit 实现分页 select * from xxx limit m,n # m 表示从第几条数据开始&#xff0c;默认从0开始 # n 表示查询几条数据 select * from xxx limit 2,3 # 从索引为2的数据开始&#xff0c;往后查询三个。2、3、4 (1) 创建分页对象&#xff0c;用来封装分页的数据 PS…...

RPC通信原理解析

一、什么是RPC框架&#xff1f; RPC&#xff0c;全称为Remote Procedure Call&#xff0c;即远程过程调用&#xff0c;是一种计算机通信协议。 比如现在有两台机器&#xff1a;A机器和B机器&#xff0c;并且分别部署了应用A和应用B。假设此时位于A机器上的A应用想要调用位于B机…...

【蓝桥杯集训·周赛】AcWing 第93场周赛

文章目录第一题 AcWing 4867. 整除数一、题目1、原题链接2、题目描述二、解题报告1、思路分析2、时间复杂度3、代码详解第二题 AcWing 4868. 数字替换一、题目1、原题链接2、题目描述二、解题报告1、思路分析2、时间复杂度3、代码详解第三题 AcWing 4869. 异或值一、题目1、原题…...

蓝桥杯-刷题统计

蓝桥杯-刷题统计1、问题描述2、解题思路3、代码实现3.1 方案一&#xff1a;累加方法(超时)3.2 方案二1、问题描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a 道题目, 周六和周日每天做 b 道题目。请你帮小明计算, 按照计划他将在 第几天实现做题数…...

Linux入门教程||Linux Shell 变量|| Shell 传递参数

Shell 变量 定义变量时&#xff0c;变量名不加美元符号&#xff08;$&#xff0c;PHP语言中变量需要&#xff09;&#xff0c;如&#xff1a; your_name"w3cschool.cn"注意&#xff0c;变量名和等号之间不能有空格&#xff0c;这可能和你熟悉的所有编程语言都不一…...

[算法和数据结构]--回溯算法之DFS初识

回溯算法——DFSDFS介绍(Depth First Search)DFS经典题目1. 员工的重要性2. 图像渲染3.被围绕的区域4.岛屿数量5. 电话号码的字母组合6.数字组合7. 活字印刷8. N皇后DFS介绍(Depth First Search) 回溯法&#xff08;back tracking&#xff09;&#xff08;探索与回溯法&#x…...

【LeetCode每日一题】——680.验证回文串 II

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 贪心算法 二【题目难度】 简单 三【题目编号】 680.验证回文串 II 四【题目描述】 给你一个字…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...