当前位置:网站首页>进程(下):进程控制、终止、等待、替换
进程(下):进程控制、终止、等待、替换
2022-08-02 03:32:00 【RNGWGzZs】

--------------“美好的事总会如约而至”
(1)进程控制:
① 如何理解fork有两个返回值?
父:子 ==1:N; 父进程不需要表示,子进程需要标识。
多个子进程执行不同任务,父进程需要通过id 区分子进程。

因此调用fork时候,内核会做:
1.分配新的内存块 和 内核数据 给子进程。
2.将父进程的代码 数据拷贝给子进程。
3.并把子进程添加到 系统进程调用列表当中。
4.fork返回,并执行调度。
②写时拷贝:
通常情况下,父子代码共享,数据也是(物理内存是一样的)。但是当一方试图写入时,为了保证各个进程的独立性,此时会发生写时拷贝。


为什么要写时拷贝?
①保证进程的独立性。
为什么不创建时就分开?
因为子进程不一定需要父进程的所有数据。
子进程不一定立马使用(按需分配);因此进行延时分配,本质是高效使用内存空间。
fork调用失败原因?
1.系统中太多程序
2.用户进程超过限制(OS进行的限制)。
(2)进程终止:
①进程退出码:
main函数返回值给了谁?操作系统
main函数也是函数,所以一定会被调用。返回值会返回给操作系统。
为什么要有返回值? ------------运行加载,完成工作,需要知道完成度。
途径:
echo $?
退出码0 、!0:
#include<string.h>
strerror(size_t i); //错误码

每种错误码,都有对应的错误含义。但这都是人为规定。
②进程退出:
1.exit:进程终止;并释放缓冲区的数据
_exit:进程终止,不做其余工作


2.异常退出:此时退出码已经没有任何意义了
3.进程终止,操作系统会做什么? 一定要去管理!
释放内存 数据结构 调度队列移除。
(3)进程等待:父进程等待
①等待必要性:回收子进程、获取其退出信息。
②进程等待方法:
1.wait:等待接收子进程返回的pid
#include<sys/wait.h>
pid_t wait(int* status)

小结:父进程通过wait 读取子进程的信息,僵尸状态也就自动改变。
在子进程运行期间(wait),父进程在做什么? 什么也没做------> 阻塞等待!!!
2.waitpid:指定等待进程
//记录子进程的状态
waitpid(pid_id pid,int* status,int options)
//有列表的监控脚本
while :; do ps ajx|head -1 && ps ajx | grep myproc |grep -v 'grep';echo "#########################" ; sleep 1 ;done;等待成功!=子进程运行成功。
status:退出结果 ---------->查看子进程 运行状态



注:进程异常终止,本质上是因为收到信号。其退出码也没有任何价值。

此进程发生异常,收到信号,此时退出码也没有任何意义。
实际中一般用 宏检测:
WIFEXITED(status) //进程信号 0 与 !0
WEXITSTATUS(status) //进程退出码多进程创建与等待:


补充:阻塞与非阻塞
//若pid没有返回 也就是子进程没有执行结束,不再等待子进程 返回0 不予等待
// 若正常退出 则返回子进程pid
pid_t ret=waitpid(id,&status,WNOHANG);

所以对父进程而言,需要不断去等子进程执行完。

(4)进程替换:
子进程执行新的进程。
进程替换函数:
| 函数 | .... |
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[]); | 数组+默认路径 |
int execve(const char *path, char *const argv[], char *const envp[]); | 数组+自定义路径 |

execl 其本质就是让程序加载到磁盘。
1.当前进程 再进行 程序替换,是否创建了新进程?
这里根本没有 创建新进程。只是把磁盘代码进行替换了而已。 进程!=可执行程序。
2.被替换后,后续的代码,是否能被读到?
答案是不能。

3. 函数调用失败,程序不会受到影响。但调用成功则不会返回!

4.运行具有独立性父子之间不会因为程序替换函数而受到影响。
函数接口的理解:

只需要理解 数组、列表 执行程序的参数的区别:
execv为例:

理解默认路径、自定义路径:
默认路径:

自定义路径(execle):

打印出null;

此时还不会打印出 这个未定义(MAVAL)的环境变量。


进程的相关内容也最后完结:希望对阅读的你有用。
祝你好运~
边栏推荐
猜你喜欢
随机推荐
振芯科技GM8285C:功能TTL转LVDS芯片简介
n皇后问题(回溯法)
判断子序列 —— LeetCode-392
D类音频功放NS4110B电路设计
树莓派4B打开文件管理时出现闪退
读取FBX文件踩坑清单
TC358860XBG BGA65 东芝桥接芯片 HDMI转MIPI
开源代码交叉编译操作流程及遇到的问题解决(lightdm)
树莓派入门(1)系统镜像烧录
How to quickly build your own IoT platform?
GM8775C MIPI转LVDS调试心得分享
【nRF24L01 connects with Arduino to realize wireless communication】
【Arduino 连接 SD 卡模块实现数据读写】
OneNET Studio与IoT Studio对比分析
【Arduino 连接GP2Y1014AU0F 灰尘传感器】
使用飞凌嵌入式IMX6UL-C1板子——qt+opencv环境搭建
博达工业云与阿里云对比
【土壤湿度传感器与 Arduino 测量土壤湿度】
[Arduino connects the clock module to display the time on LCD1602]
【Popular Science Post】Detailed explanation of MDIO interface









