当前位置:网站首页>进程(下):进程控制、终止、等待、替换
进程(下):进程控制、终止、等待、替换
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)的环境变量。


进程的相关内容也最后完结:希望对阅读的你有用。
祝你好运~
边栏推荐
猜你喜欢

本地数据库 sqlite3 编译和使用

【Popular Science Post】Detailed explanation of MDIO interface

阿里云华为云对比分析

TQP3M9009电路设计

【Arduino连接时钟模块在LCD1602上显示时间】

Comparative analysis of OneNET Studio and IoT Studio

GM7150,振芯科技,视频解码器,CVBS转BT656/601,QFN32,替换TVP5150/CJC5150

最第k大的数的一般性问题

字符串匹配(蛮力法+KMP)

Modify hosts file using batch script
随机推荐
功率计,物联网,智能插座电路设计【毕业设计】
【MQ-2 可燃气体和烟雾传感器与 Arduino 配合使用】
【plang 1.4.5】编写坦克(双人)游戏脚本
HDMI转MIPI CSI东芝转换芯片-TC358743XBG/TC358749XBG
LT8918L LVDS转MIPI芯片技术支持资料
Arduino点亮数码管
AD8361检波器
C语言教程 - 制作单位转换器
[DS3231 RTC real-time clock module and Arduino interface to build a digital clock]
使用Vercel托管自己的网站
Host your own website with Vercel
引擎开发日志:集成Bullet3物理引擎
判断子序列 —— LeetCode-392
【树莓派入门(2)树莓派的远程控制】
【土壤湿度传感器与 Arduino 测量土壤湿度】
【科普贴】UART接口通讯协议
与TI的lvds芯片兼容-GM8284DD,GM8285C,GM8913,GM8914,GM8905C,GM8906C,国腾振芯LVDS类芯片,
振芯GM7123C:功能RGB转VGA芯片方案简介
GM8284DD,GM8285C,GM8913,GM8914,GM8905C,GM8906C,国腾振芯LVDS类芯片
GM7150 CVBS转BT656视频解码芯片详细内容及设计要求