进程控制(Linux)上

简介: 进程控制(Linux)

进程创建


fork函数初识


fork函数的功能是在已经存在的进程中创建一个子进程


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


返回值:创建失败返回-1;创建成功,子进程返回0,父进程返回子进程的进程id;可以进行简单的类比:父亲可以有多个孩子,但是孩子却只有一个父亲,所以进程创建之后需要将孩子的id给父亲,而子进程只需要getpid()就可以获取自己的id


49c4ce30d440c115dd0865288427f0a2_eb33cab3d1ee4635bbed9f3f13060c85.png

b19502826bc39ddbb94978bf072b0491_a2f69103cea7499990eccfb57e8b0863.png


进程调用fork函数后,操作系统会分配新的内存块和内核数据结构给子进程;将父进程部分数据结构内容拷贝到子进程中;将子进程添加到进程列表中


fork函数返回值


为什么fork函数会有两个返回值呢?而且为什么返回之后,给父进程赋值子进程的id,给子进程赋值为0呢?为什么同一个返回值可以让if else同时成立呢?

接下来,深入了解该函数


首先用户使用fork函数,操作系统开始调用函数完成相应的任务


91f1e7d8515aca5623b36b42d9d45260_a8b04693599c427aac95153794c12986.png


当函数fork()准备return pid;时,核心代码已经执行完毕,子进程也已经创建完成,并且在操作系统的运行队列中,准备被调度;所以,在执行return pid;之前,父子进程已经分流,可分别执行return pid;语句;返回的本质就是写入,子进程或父进程谁先返回,谁先写入id中,由于写时拷贝,同一个id会有两个不同的内容,根据不同的内容和判断语句if else进行匹配


fork常规用法


父进程希望复制自己,使父子进程同时执行不同的代码段

父进程希望子进程执行另一个不同的程序


fork调用失败的原因


系统中有太多的进程

实际用户的进程数超过限制


进程终止


进程退出场景


代码运行完毕,结果正确

代码运行完毕,结果错误

代码异常运行终止


进程常见退出方法


先介绍退出码,到目前为止,所写的代码中在最后都会加上 return 0;为什么一定是数字0,而不是其他数字呢???

进程退出时,会返回对应的退出码,标识进程执行的结果是否中正确;一般而言退出码都必须有对应的文字描述

退出码:0表示程序正常运行;!0具体的数字表示不同的错误


程序正常终止

可以通过 echo $查看最近一次的进程退出码


c44881cb28580447eea84a95c1d265f1_c482c599217e4390951fe66ec92c4cd2.png


return 返回


调用exit

14469d3805a50462e158c91099111e9d_2177ef0f3b7a47c59b62980872ff8da4.png

2bfbd9b3f876aca4c1fd8c755edd90b3_1c8a18e84c8643a8945dc4896077c11e.png

程序并没有立刻打印 hello world,而是两秒之后再打印的;而且退出码也与程序中exit(1)所设置的一致


调用_exit

786b1d9ffaa2398c98cff76363549617_c52a5cb40fe04d28bbe17b497cd0c686.png

aa8351c76fbb5df2ddc96ddcce603a7c_6462807dae7747a9b215a3c166f6a6e6.png

程序压根就没有打印hello world,退出码仍是一致的


原因如下:

exit终止进程,主动刷新缓冲区

_eixt终止进程,不会刷新缓冲区


两者区别:exit是库函数;_exit是系统调用


0c19b5502cf468f63334b4cd9c6c1f23_f533613523714418ab2a62a4ef4781b7.png


return函数


return是较为常见的退出进程的方式,执行return n等同于执行exit(n)


进程等待


进程等待必要性


如果子进程退出,父进程一直不能获取其状态,就会造成子进程变成僵尸状态,进而造成内存泄漏


如果进程变成僵尸状态,操作系统也无能为力


父进程创建子进程的目的便是为了完成任务,所以需要知道子进程运行是否完成,结果正确与否,是否正常退出


父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息


获取子进程status


进程等待的方法


wait/waitpid,都有一个 status参数,该参数是一个输出型参数,由操作系统填充

如果传递NULL,表示不关心子进程的退出状态信息(子进程阻塞)

操作系统会根据该参数,将子进程的退出信息反馈给父进程

status不能简单地作为整体来看待,位图如下:信号等于0表示正常退出,退出状态就是退出码(位图在后面的学习中再详细学习)

status&0x7F进程退出信息;status >>8)&0xFF获取进程退出状态


0e63c15d1920c61481fa61727770bc30_c8e5eb81aa934ae3812c9fe84f331e9e.png


wait方法


#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);


返回值:如果成功,返回被等待进程的id;如果失败,返回-1

参数:输出型参数,获取子进程退出状态,不关心可设置为NULL;


4733492022a96719965af5190794fa85_1344980a700f45c682c14caa27216f2a.png

2eb2557e7f33f4e90d5556d893fb698e_bec67d0e05e44c6c877650816331a525.png

378baf4400fd5e471c8814552b504f44_9094d62068054560bfaed7012f6568ad.png


前十秒一直在子进程中运行,状态是S+;十秒到十五秒之间,子进程终止运行,处于僵尸进程Z+;十五秒后父进程通过wait将子进程资源回收


waitpid方法


#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid,int*status,int options);


返回值:如果成功,返回子进程的id;如果设置了选项WNOHANG,但是waitpid并没有已退出的子进程可以收集,则返回0;如果失败,返回-1,此时errno会被设置成相应的值以指示错误


参数:

pid:子进程id


status:WIFEXITED:若正常终止子进程,则为真,查看进程是否正常退出;WEXITSTATUS:若WIFEXIT非零,则提取进程退出码,查看进程的退出码


options:

0默认为阻塞状态;WNOHANG(非阻塞):若pid指定的子进程没有结束,则waitpd函数返回0,不予等待;若进程正常结束,则返回该子进程的id


913aa576d7c82ccb3b2ce712869cd071_b74640767acd4f929dad44dcfffcce54.png

cea11e9ce377d453e44ee0132dfadd2f_b1588cf949e04dc9a89eb1f15f71b821.png


status获取子进程信息的过程:子进程退出后,将退出状态,终止信息保存至PCB中;父进程系统调用waitpid,通过status获取子进程的退出状态,终止信息


a705f41ba25b01319d2b5b1388dd0e4f_25f7b20526664c75aed18745334615aa.png


通过宏获取status


83977b716ec8b59035637d0924f00659_8237f64fe4c0492ab8dbfb84fd04ac37.png

b132d893a330485841ad80ee5ebce8f6_5809d9a95ab643c9baaa0dbbfbfe169b.png


阻塞VS非阻塞


阻塞:当父进程等待获取子进程资源时,如果子进程还未退出,父进程就一直在等其退出;非阻塞:当父进程等待获取子进程资源时,如果子进程还未退出,父进程可以去执行其他其他程序,不需要一直等待子进程,采取轮询


pid_t waitpid(pid_t pid,int*status,int options);中, option值为0时代表阻塞状态; option为WNOHANG时代表非阻塞


阻塞状态上面已经展示过,接下来展示非阻塞获取子进程资源


e456fdaec89f58f937b01ef21fbd818b_4c0b9ba826d041aeb403550f2719515d.png

b6681e1132bba48c1651f35f7f642824_27d3903f833c45c896328c3b72ea8d49.png


waitpid返回值:等于零,调用成功,但是子进程并没有退出;大于零,调用成功并且子进程也退出;小于零,调用失败


  1. 如果子进程已经退出,调用wait/waitpid时,会立刻返回,并释放资源,获取子进程退出信息
  2. 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能会阻塞
  3. 如果不存在该子进程,则立刻出错返回


相关实践学习
CentOS 7迁移Anolis OS 7
龙蜥操作系统Anolis OS的体验。Anolis OS 7生态上和依赖管理上保持跟CentOS 7.x兼容,一键式迁移脚本centos2anolis.py。本文为您介绍如何通过AOMS迁移工具实现CentOS 7.x到Anolis OS 7的迁移。
目录
相关文章
|
6月前
|
监控 Linux 应用服务中间件
探索Linux中的`ps`命令:进程监控与分析的利器
探索Linux中的`ps`命令:进程监控与分析的利器
130 13
|
5月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
5月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
182 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
|
4月前
|
算法 Linux 调度
探索进程调度:Linux内核中的完全公平调度器
【8月更文挑战第2天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。本文将深入探讨Linux内核中的完全公平调度器(Completely Fair Scheduler, CFS),一个旨在提供公平时间分配给所有进程的调度器。我们将通过代码示例,理解CFS如何管理运行队列、选择下一个运行进程以及如何对实时负载进行响应。文章将揭示CFS的设计哲学,并展示其如何在现代多任务计算环境中实现高效的资源分配。
|
5月前
|
存储 缓存 安全
【Linux】冯诺依曼体系结构与操作系统及其进程
【Linux】冯诺依曼体系结构与操作系统及其进程
173 1
|
5月前
|
小程序 Linux
【编程小实验】利用Linux fork()与文件I/O:父进程与子进程协同实现高效cp命令(前半文件与后半文件并行复制)
这个小程序是在文件IO的基础上去结合父子进程的一个使用,利用父子进程相互独立的特点实现对数据不同的操作
114 2
|
5月前
|
SQL 自然语言处理 网络协议
【Linux开发实战指南】基于TCP、进程数据结构与SQL数据库:构建在线云词典系统(含注册、登录、查询、历史记录管理功能及源码分享)
TCP(Transmission Control Protocol)连接是互联网上最常用的一种面向连接、可靠的、基于字节流的传输层通信协议。建立TCP连接需要经过著名的“三次握手”过程: 1. SYN(同步序列编号):客户端发送一个SYN包给服务器,并进入SYN_SEND状态,等待服务器确认。 2. SYN-ACK:服务器收到SYN包后,回应一个SYN-ACK(SYN+ACKnowledgment)包,告诉客户端其接收到了请求,并同意建立连接,此时服务器进入SYN_RECV状态。 3. ACK(确认字符):客户端收到服务器的SYN-ACK包后,发送一个ACK包给服务器,确认收到了服务器的确
193 1
|
6月前
|
Web App开发 运维 监控
深入探索Linux命令pwdx:揭秘进程工作目录的秘密
`pwdx`命令在Linux中用于显示指定进程的工作目录,基于`/proc`文件系统获取实时信息。简单易用,如`pwdx 1234`显示PID为1234的进程目录。结合`ps`和`pgrep`等命令可扩展使用,如查看所有进程或特定进程(如Firefox)的目录。使用时注意权限、进程ID的有效性和与其他命令的配合。查阅`man pwdx`获取更多帮助。
|
6月前
|
存储 Shell Linux
Linux进程概念(下)
本文详细的介绍了环境变量和进程空间的概念及其相关的知识。
39 0
Linux进程概念(下)
|
5月前
|
缓存 Linux 编译器
【Linux】多线程——线程概念|进程VS线程|线程控制(下)
【Linux】多线程——线程概念|进程VS线程|线程控制(下)
72 0