进程控制(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. 如果不存在该子进程,则立刻出错返回


目录
相关文章
|
1天前
|
存储 安全 Linux
【Linux】详解进程通信中信号量的本质&&同步和互斥的概念&&临界资源和临界区的概念
【Linux】详解进程通信中信号量的本质&&同步和互斥的概念&&临界资源和临界区的概念
|
1天前
|
存储 Linux Shell
Linux:进程等待 & 进程替换
Linux:进程等待 & 进程替换
27 9
|
1天前
|
存储 Linux C语言
Linux:进程创建 & 进程终止
Linux:进程创建 & 进程终止
23 6
|
1天前
|
存储 Linux Shell
Linux:进程概念
Linux:进程概念
17 8
|
1天前
|
算法 Linux 调度
xenomai内核解析--xenomai与普通linux进程之间通讯XDDP(一)--实时端socket创建流程
xenomai与普通linux进程之间通讯XDDP(一)--实时端socket创建流程
6 1
xenomai内核解析--xenomai与普通linux进程之间通讯XDDP(一)--实时端socket创建流程
|
1天前
|
Linux 调度 数据库
|
1天前
|
存储 缓存 Linux
xenomai内核解析--xenomai与普通linux进程之间通讯XDDP(三)--实时与非实时数据交互
本文介绍了Xenomai中的XDDP(Xenomai Distributed Data Protocol)通信机制,XDDP用于实时和非实时进程之间的数据交换。XDDP在Xenomai内核中涉及的数据结构和管理方式,以及创建XDDP通道后的实时端和非实时端连接过程。
7 0
xenomai内核解析--xenomai与普通linux进程之间通讯XDDP(三)--实时与非实时数据交互
|
2天前
|
Shell Linux
【Linux】进程实践项目(更新中) — 自主shell编写
前几篇文章,我们学习进程的相关知识:进程概念,进程替换,进程控制。熟悉了进程到底是个什么事情,接下来我们来做一个实践,来运用我们所学的相关知识。这个项目就是手搓一个shell模块,模拟实现Xshell中的命令行输入。
9 1
|
2天前
|
自然语言处理 Java Linux
【Linux】开始学习进程替换吧!
通过学习进程替换,我们可以体会到多语言混搭的快乐,可以从C语言直接蹦到python ,也可以从c++里运行java代码。是不是很厉害!这是通过调度多个进程的效果,联系我们之前学习的进程,进程控制等概念。我们可以想要运行其他代码可以通过创建子进程来实现,但是这样也肯定是同一种语言,如果想要运行其他语言,那是不是有种方法可以调度一个进程来当做子进程呢??? 我们开始今天的学习吧!
9 0
|
2天前
|
Shell Linux 编译器
【Linux】从零开始认识进程 — 中下篇
环境变量具有系统级的全局属性,因为会被子进程继承下去!!!
9 0
【Linux】从零开始认识进程 — 中下篇