前言:

        上文我们讲到了Linux中的虚拟空间地址,知道了一个进程对应一个虚拟地址空间,虚拟空间地址与物理地址之间通过页表映射....【Linux】虚拟地址空间-CSDN博客

        本文我们来讲一讲Linux系统是如何控制进程的!

        如果喜欢本期文章,请点点关注吧!非常感谢佬的支持   _(:з」∠)_                                 


进程创建

fork函数

        fork函数是Linux系统提供的接口,其功能就是创建子进程。

        既调用fork函数,系统就自动为我们创建好了子进程

#include<unistd.h>
pid_t fork();其中pid_t是Linux中的数据类型,相当于int,即为整型

        fork的返回值有两个,对于父进程:返回子进程的pid,对于子进程:返回0

#include <stdio.h>
#include <unistd.h>int main()
{pid_t pid = fork();if(pid<0){   printf("创建失败");}   else if(pid == 0){   //子进程printf("我是一个子进程:%d,这是我的父进程:%d\n",getpid(),getppid());}   else if(pid > 0){   printf("我是一个父进程:%d,这是我的父进程:%d\n",getpid(),getppid());}   
} 

        对于fork原理的详细介绍可参考【Linux】初见,进程概念-CSDN博客中的第四节“如何创建进程”,这里面有超级详细的介绍!

fork的用法

        一个父进程希望复制自己,使父子进程同时执行不同的代码段。e.g. 父进程等待客户端响应,生成子进程处理请求。

        一个进程想要执行多个不同的代码。e.g. 生成子进程调用exec函数。

fork失败原因

        系统中的进程太多了

        用户的进程数量超过了限制


进程终止

进程终止的本质就是进程结束,系统释放资源:释放进程申请的相关数据结构和对应的代码与数据

进程退出的场景

        1.代码运行完毕,结果正确(退出码为0)

        2.代码运行完毕,结果不正确(退出码为非0)

        3.代码异常终止(进程接收到型号终止,退出码无意义)

进程退出方法

正常退出:

        1.从main函数返回

        2.调用exit

        3._exit

异常退出:

        信号终止

退出码

        退出码可以告诉我们进程终止时的状态,0代表执行成功,非0则代表不成功

        非0的退出码中,一个值对应一个错误原因。可以使用strerror函数获取退出码对应的信息。

#include <stdio.h>
#include<string.h>int main()
{for(int i=0;i<200;i++){   printf("%d -> %s\n",i,strerror(i));                                                                                                                            }   
}
0 -> Success
1 -> Operation not permitted
2 -> No such file or directory
3 -> No such process
4 -> Interrupted system call
5 -> Input/output error
6 -> No such device or address
7 -> Argument list too long
8 -> Exec format error
9 -> Bad file descriptor
10 -> No child processes
11 -> Resource temporarily unavailable
12 -> Cannot allocate memory
13 -> Permission denied
14 -> Bad address
15 -> Block device required
16 -> Device or resource busy
17 -> File exists
18 -> Invalid cross-device link
19 -> No such device
20 -> Not a directory
21 -> Is a directory
22 -> Invalid argument
23 -> Too many open files in system
24 -> Too many open files
25 -> Inappropriate ioctl for device
26 -> Text file busy
27 -> File too large
28 -> No space left on device
29 -> Illegal seek
30 -> Read-only file system
31 -> Too many links
32 -> Broken pipe
33 -> Numerical argument out of domain
34 -> Numerical result out of range
35 -> Resource deadlock avoided
36 -> File name too long
37 -> No locks available
38 -> Function not implemented
39 -> Directory not empty
40 -> Too many levels of symbolic links
41 -> Unknown error 41
42 -> No message of desired type
43 -> Identifier removed
44 -> Channel number out of range
45 -> Level 2 not synchronized
46 -> Level 3 halted
47 -> Level 3 reset
48 -> Link number out of range
49 -> Protocol driver not attached
50 -> No CSI structure available
51 -> Level 2 halted
52 -> Invalid exchange
53 -> Invalid request descriptor
54 -> Exchange full
55 -> No anode
56 -> Invalid request code
57 -> Invalid slot
58 -> Unknown error 58
59 -> Bad font file format
60 -> Device not a stream
61 -> No data available
62 -> Timer expired
63 -> Out of streams resources
64 -> Machine is not on the network
65 -> Package not installed
66 -> Object is remote
67 -> Link has been severed
68 -> Advertise error
69 -> Srmount error
70 -> Communication error on send
71 -> Protocol error
72 -> Multihop attempted
73 -> RFS specific error
74 -> Bad message
75 -> Value too large for defined data type
76 -> Name not unique on network
77 -> File descriptor in bad state
78 -> Remote address changed
79 -> Can not access a needed shared library
80 -> Accessing a corrupted shared library
81 -> .lib section in a.out corrupted
82 -> Attempting to link in too many shared libraries
83 -> Cannot exec a shared library directly
84 -> Invalid or incomplete multibyte or wide character
85 -> Interrupted system call should be restarted
86 -> Streams pipe error
87 -> Too many users
88 -> Socket operation on non-socket
89 -> Destination address required
90 -> Message too long
91 -> Protocol wrong type for socket
92 -> Protocol not available
93 -> Protocol not supported
94 -> Socket type not supported
95 -> Operation not supported
96 -> Protocol family not supported
97 -> Address family not supported by protocol
98 -> Address already in use
99 -> Cannot assign requested address
100 -> Network is down
101 -> Network is unreachable
102 -> Network dropped connection on reset
103 -> Software caused connection abort
104 -> Connection reset by peer
105 -> No buffer space available
106 -> Transport endpoint is already connected
107 -> Transport endpoint is not connected
108 -> Cannot send after transport endpoint shutdown
109 -> Too many references: cannot splice
110 -> Connection timed out
111 -> Connection refused
112 -> Host is down
113 -> No route to host
114 -> Operation already in progress
115 -> Operation now in progress
116 -> Stale file handle
117 -> Structure needs cleaning
118 -> Not a XENIX named type file
119 -> No XENIX semaphores available
120 -> Is a named type file
121 -> Remote I/O error
122 -> Disk quota exceeded
123 -> No medium found
124 -> Wrong medium type
125 -> Operation canceled
126 -> Required key not available
127 -> Key has expired
128 -> Key has been revoked
129 -> Key was rejected by service
130 -> Owner died
131 -> State not recoverable
132 -> Operation not possible due to RF-kill
133 -> Memory page has hardware error

        使用echo $?,可以打印出最近一个程序的退出码。

        退出码是进程的性质之一,所以退出码会保存到进程的PCB中。

_exit函数

#include<unistd.h>
void _exit(int status);在任何地方调用_exit函数,都会让当前进程结束
并以给定的值作为退出码退出

exit函数

#include<unistd.h>
void exit(int status);与_exit函数功能类似
都是以指定的退出码,退出当前进程

区别

        _exit函数系统调用,而exit是C语言提供。

        使用exit函数退出时,会进行缓冲区的刷新。反之_exit则不会。

举个例子说明:

        程序结束刷新缓冲区,信息打印在屏幕上,反之没有信息打印

        感兴趣的朋友可以看看这篇文章,这里有详细的缓冲区刷新介绍【Linux】LInux下第一个程序:进度条-CSDN博客

#include <stdio.h>
#include<string.h>
#include<unistd.h>int main()
{printf("yuzuriha");sleep(1);exit(0);                                                                                                                                                           
}

#include <stdio.h>
#include<string.h>
#include<unistd.h>int main()
{printf("yuzuriha");                                                                                                                                                sleep(1);_exit(0);
}


进程等待

进程等待的必要性

        1.之前我们讲过子进程的退出后,子进程回进入僵尸状态,必须要被父进程回收才行。若子进程一直没有被父进程回收,就会一直处于僵尸状态,进而造成内存泄漏。

        2.进程被创造出来执行任务,结果如何,是成功、失败还是异常,这是父进程要得知的必要信息。

        所以回收子进程是必要的,父进程通过进程等待的方式,回收子进程进程资源、获取子进程的退出信息。

进程等待的方法

wait方法
#include<sys/types.h>
#include<sys/wait.h>pid_t wait(int* status);返回值:等待成功返回对应的子进程pid,失败则返回-1参数status:为输出型参数,可以获取子进程的退出码若不需要,可以传NULL忽略这个参数
waitpid函数
#include<sys/types.h>
#include<sys/wait.h>pid_ t waitpid(pid_t pid, int *status, int options);

下面详细介绍一下每一个参数:

pid_t pid

参数pid:-1,表示可以等待任意一个子进程。

参数pid:>0,表示只能等待当前这个进程的子进程。

status

        如上面所讲,status是一个输出型参数,由操作系统填充,我们可以通过status获取进程状态

        status并不是一个简单的整型,细节如下:

        1.status是一个低16位有效的int,通过位划分存储子进程的信息

        2.正常终止的情况下:低7位全为0,15~8存放退出码

                获取退出码:WEXITSTATUS(status)

        3.非正常退出:退出码无意义,第7位存放标志,6~0存放信号编号

                判断一个进程是否位正常退出:WIFEXITED(status),正常为真。

options

        options的默认值是0,表示阻塞等待

        options为:WNOHANG时表示非阻塞等待

        简而言之,阻塞等待就是等待子进程结束的过程中,父进程不能运行。而非阻塞等待,就是等待过程中父进程可以执行自己的代码。

        当参数为:WNOHANG时,waitpid会进行非阻塞轮询等待结束,返回>0(pid)本次调用结束,但子进程还没有退出,返回0调用失败,返回<0;


进程程序替换 

        程序替换就是字面上的意思,替换掉原有的程序,先来直接看看效果

#include <stdio.h>                                                                                                                                                     
#include<unistd.h>int main()
{printf("开始\n");execl("/usr/bin/ls","ls","-l",NULL);printf("结束\n");
}

         我们可以看到执行就第一个printf打印出了结果,第二行就执行就程序替换,将原来的程序替换为了ls指令。

替换原理

        exec系列函数,其功能就是用新的程序替换原本的程序。

        如图,替换程序的本质是将物理内存中的数据,用新数据覆盖,页表中的物理地址重新覆盖填写,其他的不动。

注意:

        1.一旦程序替换成功,就会去执行新代码了,旧代码以及不复存在了。

        2.exec系列函数只有在失败的时候才有返回值,既只要返回就是失败。

        3.程序替换并没有创建新进程,只是进行了数据的覆盖。

认识全部exec函数

execl
int execl(const char* path , const char* arg , ...)l:代表list,以链表的形式传参
path:路径+程序名,表示要执行谁
arg:平时怎么写指令,这里就怎么写。表示如何执行注:一定要以NULL结尾!!!
#include <stdio.h>                                                                                                                                                     
#include<unistd.h>int main()
{printf("开始\n");execl("/usr/bin/ls","ls","-l",NULL);printf("结束\n");
}

不仅可以替换系统程序,也可以替换我们自己写的程序:

#include <stdio.h>
#include<unistd.h>int main()
{printf("开始\n");execl("./x","./x",NULL);                                                                                                                                           printf("结束\n");
}

        我们知道数据和代码父子进程默认是共享的,那程序替换对父进程有影响吗?

        没有,因为数据和代码都会进行写时拷贝

execlp
int execlp(const char* file , const char* arg , ...)l:表示list,以链表的形式传参
p:表示环境变量PATHfile:有了PATH环境变量,我们就不用写路径了。直接写我们要执行的程序名即可
arg:同上,与我们平时写的指令无异但必须以NULL结尾
#include <stdio.h>
#include<unistd.h>int main()
{printf("开始\n");execlp("ls","ls","-l",NULL);                                                                                                                                       printf("结束\n");
}

execv
int execv(const char* path , char* const argv[])v:表示vector,用数组的方式传参数组中,依旧想要以NULL结尾
#include <stdio.h>
#include<unistd.h>int main()
{char* const argv[]={(char* const)"ls",(char* const)"-l",NULL};  printf("开始\n");execv("/usr/bin/ls",argv);                                                                                                                                         printf("结束\n");
}

 execvp
int execvp(const char* file , char* const argv[])v:vector,以数组形式传参
p:环境变量PATH

同上,就不举例了

execvpe
int execvpe(const char* flie , char* const argv[] , char* cosnt envp[])相比上面,多了一个e
e:环境变量!传入envp数组,那被替换的进程的环境变量会被evnp[]直接覆盖
这会导致我们无法使用原来的环境变量

        所以我们一般采用新增环境变量的方式,而不是直接覆盖。

        法一:调用系统调用:putevn(char* string)新增环境变量,再调用其他exec函数实现

        法二:调用系统调用:putevn(char* string)新增环境变量,调用execvpe时,传入环境变量指针:environ

execle
int execle(const char* path , char* const argv .... , char* cosnt envp[])同上
execve
int execve(const char* path , char* const argv[] ... , char* cosnt envp[])同上

值得一提的是execve的系统调用,而其他函数都是C语言提供的

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Matplotlib(五)- 绘制子图

文章目录一、子图概述1. 子图介绍2. 子图布局2.1 网格布局2.2 自由布局二、绘制等分区域子图1. 使用 plt.subplot() 绘制子图示例&#xff1a;绘制多个子图示例&#xff1a;工业月度同比情况2. 使用 plt.subplots() 绘制子图示例&#xff1a;绘制多个子图示例&#xff1a;部分国…

C++中互斥锁、共享锁深度解析

一&#xff0c;互斥锁互斥锁&#xff08;Mutex&#xff0c;全称 Mutual Exclusion&#xff09;是并发编程中用于保护共享资源的核心同步机制。它通过确保同一时间仅有一个线程访问临界区&#xff08;Critical Section&#xff09;&#xff0c;解决多线程环境下的数据竞争和不一…

Qt中的QWebSocket 和 QWebSocketServer详解:从协议说明到实际应用解析

前言 本篇围绕 QWebSocket 和 QWebSocketServer&#xff0c;从协议基础、通信模式、数据传输特点等方面展开&#xff0c;结合具体接口应用与实战案例进行说明。 在实时网络通信领域&#xff0c;WebSocket 技术以其独特的全双工通信能力&#xff0c;成为连接客户端与服务器的重要…

机器学习 —— 决策树

机器学习 —— 决策树&#xff08;Decision Tree&#xff09;详细介绍决策树是一种直观且易于解释的监督学习算法&#xff0c;广泛应用于分类和回归任务。它通过模拟人类决策过程&#xff0c;将复杂问题拆解为一系列简单的判断规则&#xff0c;最终形成类似 “树” 状的结构。以…

车规MCU软错误防护技术的多维度分析与优化路径

摘要&#xff1a;随着汽车电子技术的飞速发展&#xff0c;微控制单元&#xff08;MCU&#xff09;在汽车电子系统中的应用日益广泛。然而&#xff0c;大气中子诱发的单粒子效应&#xff08;SEE&#xff09;对MCU的可靠性构成了严重威胁。本文深入探讨了软错误防护技术在车规MCU…

原生微信小程序实现语音转文字搜索---同声传译

效果展示 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/23257ce3b6c149a1bb54fd8bc2a05c68.png#pic_center 注意&#xff1a;引入同声传译组件请看这篇文章 1.search.wxml <view class"search-page"><navigation-bar title"搜索" …

Wireshark安装过程缺失vc_runtimeMinimum_x64.msi文件,安装 Visual C++ Redistributable

一、我大意了 一开始是Npcap装不上。 在这个网站下的&#xff1a; Wireshark (kafan58.com) 安装程序&#xff1a; 安装过程&#xff1a; 无语死了&#xff0c;感觉被骗了......外网下的才是最正版的。 二、外网正版 下载最新的4.4.8版本Wireshark重新安装 2.1 vc_runtime…

高通平台Wi-Fi Display学习-- 调试 Wi-Fi Display 问题

4.1 调试 WFD 性能 4.1.1 通过启用调节器模式验证 WFD 当系统设为调节器模式时,设备的运行时钟将达到峰值。要在系统中启用调节器模式,应 在序列中输入以下命令: 1. adb shell stop mpdecision 2. adb shell echo 1→/sys/devices/system/cpu/cpu1/online 3. adb shell…

5G专网与SD-WAN技术融合:某饮料智能工厂网络架构深度解析

随着工业互联网的快速发展&#xff0c;制造业正从传统的生产模式向智能化、数字化方向转型。某饮料智能工厂项目创新性地引入了5G专网与SD-WAN技术&#xff0c;形成了“连接-计算-应用-安全”的全链条网络架构。本文将深入剖析这两种技术在智能工厂中的应用场景、部署架构&…

Java项目:基于SSM框架实现的公益网站管理系统【ssm+B/S架构+源码+数据库+毕业论文+答辩PPT+远程部署】

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本公益网站就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&#x…

向华为学习——IPD流程体系之IPD术语

第一章 IPD体系 1.1集成产品开发IPD Integrated Product Development,IPD是一种领先的、成熟的产品开发的管理思想和管理模式。它是根据大量成功的产品开发管理实践总结出来的,并被大量实践证明的高效的产品开发模式。通过IPD,可建立起基于市场和客户需求驱动的集成产品开…

落霞归雁:从自然之道到“存内计算”——用算法思维在芯片里开一条“数据高速航道”

作者 落霞归雁&#xff08;CSDN首发&#xff0c;转载请注明&#xff09; 段落一 现象&#xff1a;当“摩尔”老去&#xff0c;数据却在狂奔 过去 30 年&#xff0c;CPU 频率翻了 60 倍&#xff0c;而 DRAM 带宽只翻了 20 倍。算力与带宽的剪刀差&#xff0c;让“计算”变成“等…

StyleX:Meta推出的高性能零运行时CSS-in-JS解决方案

简介 StyleX 是由 Meta 开发的零运行时 CSS-in-JS 解决方案&#xff0c;在构建时将样式编译为静态 CSS&#xff0c;消除运行时开销。 核心特性 零运行时开销 – 构建时编译为静态 CSS类型安全 – 完整的 TypeScript 支持原子化 CSS – 自动生成原子化类名&#xff0c;最小化…

LINUX 85 SHElL if else 前瞻 实例

问题 判断用户是否存在 id user id $user变量判断vsftpd软件包被安装 rpm -q vsftpd rpm -ql vsftpd >& null[rootweb ~]# rpm -ql vsftpd >/dev/null 2>&1 您在 /var/spool/mail/root 中有邮件yum install vsftpd 内核主版本判断 uname -rcut -d[rootweb ~]#…

2025 年非关系型数据库全面指南:类型、优势

非关系型数据库的分类与特点随着数据量呈指数级增长和数据类型日益多样化&#xff0c;传统关系型数据库在处理海量非结构化数据时面临着严峻挑战。非关系型数据库&#xff08;NoSQL&#xff09;应运而生&#xff0c;它摒弃了传统关系模型的约束&#xff0c;采用更灵活的数据存储…

深度残差网络ResNet结构

Deep Residual Learning for Image Recognition&#xff0c;由Kaiming He、Xiangyu Zhang、Shaoqing Ren和Jian Sun于2016年发表在CVPR上 1512.03385 (arxiv.org)https://arxiv.org/pdf/1512.03385 下图中&#xff0c;左侧为VGG19网络&#xff0c;中间为34层的普通网络&#xf…

python笔记--socket_TCP模拟浏览器实现

""" 1,导包 2,创建TCP套接字 3,建立连接 4,拼接客户端请求报文 5,发送请求报文 6,接收响应报文 7,过滤出html页面 8,保存为html文件 9,关闭套接字 """ # 1,导包 import socket # 2,创建TCP套接字 tcp_socketsocket.socket(socket.AF_INET,socket…

西门子PLC基础指令4:置位指令 S、复位指令 R

布尔指令 1、置位指令 S Setbit 是要进行置位操作的地址的首地址&#xff0c;N 是从该首地址开始连续置位的位数 。 LD I0.0 // 装载输入继电器I0.0的状态&#xff08;当I0.0为ON时&#xff0c;执行后续指令&#xff09; S Q0.0, 3 // 从Q0.0开始&#xff0c;连续置位3…

2.3 子组件样式冲突详解

Vue2组件样式冲突的成因与解决方案组件样式冲突的根本原因在Vue单页面应用中&#xff0c;所有组件的DOM结构最终都会合并到同一个index.html 页面中。若子组件未使用scoped属性&#xff0c;其样式会默认全局生效&#xff0c;导致不同组件中相同选择器&#xff08;如h1、.contai…

26-数据仓库与Apache Hive

1.数据仓库 是什么&#xff1f;解决什么&#xff1f;1.1 数据仓库Data Warehouse 数仓 / DW 是一个用于存储、分析、报告的数据系统.目的&#xff1a;构建面向分析的集成数据环境&#xff0c;分析结构为企业提供决策支持。数仓专注于分析数仓本身不“”生产“”数据&#xff0c…