【Linux】深入理解进程控制:从创建到终止和进程等待

请添加图片描述

文章目录

  • 进程创建
    • fork函数
    • 如何用fork函数创建子进程
    • 写实拷贝
  • 进程终止
    • 错误信息
    • exit
    • _exit
  • 进程等待
    • wait
    • waitpid
  • 总结

进程创建

fork函数

fork 函数是 Unix/Linux 系统中用于创建新进程的系统调用。调用 fork 后,当前进程(父进程)会被复制,创建出一个新的进程(子进程)。
fork函数特点:

  1. 返回值

    • 在父进程中,fork 返回子进程的 PID(进程ID)。
    • 在子进程中,fork 返回 0。
    • 如果发生错误,fork 返回 -1,并且不会创建新进程。
  2. 进程资源

    • 父进程和子进程拥有相同的代码和数据段,但各自的进程空间是独立的。
    • 子进程继承父进程的文件描述符等资源,但文件描述符的状态(如文件指针位置)是共享的。
  3. 执行顺序

    • 父进程和子进程可以并发执行,执行顺序不固定,取决于操作系统的调度策略。

如何用fork函数创建子进程

我们写一个简单的代码观察子进程的创建:

#include<unistd.h>
#include<stdio.h>
int main()
{pid_t id=fork();while(1);return 0;
}

在这里插入图片描述
可以看见子进程已经创建。

写实拷贝

“写实拷贝”是一种优化技术,常用于内存管理,特别是在进程创建和资源共享的场景中。其基本原理是:在创建新进程时,父进程和子进程共享相同的内存页,直到其中一个进程尝试修改这些内存页时,系统才会为该进程创建一个独立的副本,从而避免不必要的内存复制,提高系统性能。

当子进程创建之后,子进程以父进程的PCB为模版,创建自己的PCB,然后指向同一块资源,但是当父进程或者子进程对对应资源进行修改的时候,会发生写实拷贝。

在这里插入图片描述
原本数据块指向同一块区域的父子进程会指向不同区域。

进程终止

进程终止的常用方法:

  1. 通过main函数return
  2. exit
  3. _exit

异常退出:
Ctrl+c 信号终止

每个进程退出的时候都是有退出码的,我们来验证一下:
我们写一个简单的代码:

#include<stdio.h>
int main()
{return 10;
}

用命令查看上一次退出码:
在这里插入图片描述

可以看见退出码是10,我们再次查看一遍:
在这里插入图片描述
可以看见再次查看一遍退出信息就变成了0了,这是为什么呢?----原因就是因为我们使用的上一条命令也是一个进程,因为Linux的命令都是用C语言写的,通常运行成功都是会返回0的,所以这里查看最近一个程序的退出信息时就变成0了。
但是为什么返回0就是成功非零就是失败呢?----因为不同的数字代表不同的错误信息,系统提供了一批错误码来控制。

错误信息

在C语言中我们通常用一个全局变量来代表最近一个进程的错误码:
在这里插入图片描述
当我们创建子进程的时候也有创建失败的时候,所以当创建失败时,我们可以利用errno将错误信息打出,然后返回错误码给父进程。

#include<unistd.h>
#include<stdio.h>
#include<errno.h>
int main()
{pid_t id=fork();if(id<0){printf("error code:%d.errstring:%s\n",errno,strerror(errno));return errno;}return 0;
}

我们来看看错误码的范围:

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main()
{int i=0;for(i=0;i<200;i++){printf("errno:%d,errstring:%s\n",i,strerror(i));}return 0;
}

在这里插入图片描述
通过上面这个简单的程序我们可以知道错误码的最大值是133。
在这里插入图片描述
前面一些都是比较熟悉的错误码,操作不被允许啊,文件找不到啊,还有没有这个进程啊之类的。
比如:
在这里插入图片描述
这个的错误码就是2。
还有:
在这里插入图片描述
这个的错误码并不是3,是因为kill杀死这个进程失败了,返回1,错误码输出的就是1了。

exit

exit在程序的任何地方表示进程结束。

_exit

_exit和exit相同,唯一不同的是exit不是系统调用,而_exit是系统调用,exit内部是用系统调用封装的。

进程等待

在这里插入图片描述
关于进程等待的三个函数,我们先从第一个函数说起:

wait

wait 函数在 Unix 和 Linux 系统中用于让父进程等待其子进程结束,并收集子进程的退出状态。这个函数在进程控制中尤为重要,因为它允许父进程在子进程完成之前暂停执行,避免“僵尸进程”的出现。
一般而言父进程创建子进程就需要等待子进程,子进程结束之后将子进程的僵尸状态回收掉。
用一段代码来展示一下这个函数的用法:

#include<iostream>
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
using namespace std;
int main()
{pid_t id = fork();if(id == 0){while(1){printf("我是子进程,我是pid是%d\n",getpid());sleep(1);}}else{sleep(3);pid_t rid=wait(NULL);if(rid>0)printf("sub process wait success,sub process pid is:%d\n",rid);while(1){printf("我是父进程,我的pid是%d\n",getpid());sleep(1);}}return 0;
}

可以看见这里子进程一直运行,父进程一直是阻塞状态,一直在等待子进程结束,回收子进程。
在这里插入图片描述
我们手动杀死一下子进程。
在这里插入图片描述
在这里插入图片描述
可以看见回收成功并且返回了子进程的pid。
这里子进程结束也可能是异常结束,结束分为几种情况:

  1. 代码跑完了,结果是对的,return 0
  2. 代码跑完了,结果是错的,return !0
  3. 进程异常了

前两种很容易理解,第三种异常情况,假如我们有一个指向nullptr的指针,我们对这个指针进行操作,虚拟地址转化到物理地址的过程中就会出现异常访问,所以这里系统可能会直接将进程杀死保护物理内存。(这里系统其实是释放信号,将进程杀死的)
我们来看看有哪些信号吧:
在这里插入图片描述
这里有很多信号,几种常见的就是下面几种:
在这里插入图片描述
当我们异常访问的时候会出现段错误,当我们1/0的时候会出现浮点数错误。
我们用代码来掩饰两个错误的信号:
首先在写代码之前,我们要知道退出信息
在这里插入图片描述
要知道退出信息我们就要知道一个接口,这个接口就是:

waitpid

在这里插入图片描述
第一个参数pid表示等待某一个进程,当第一个参数大于零的时候是等待指定进程,当这个参数为-1的时候表示等待任意进程。
第二个参数表示退出信息,这个退出信息就是上面那个图,高八位是退出码,低七位是退出信号。

#include<iostream>
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<errno.h>
#include<string.h>
using namespace std;int main()
{pid_t id=fork();if(id < 0)//create fail{printf("errno code:%d,errstring:%s\n",errno,strerror(errno));}else if(id==0)//child{double result = 1/0;}else//parent{int signal=0;pid_t rid=waitpid(-1,&signal,0);if(rid>0){printf("等待成功,子进程的pid是%d,退出信号%d\n",rid,signal&0x7F);}else//wait fail{//printf fail informationprintf("wait sub process fail,exit Signal:%d\n",signal&0x7F);}}return 0;
}

可以看到这里退出信号对比上面的信号表应该是8。
在这里插入图片描述
这里可以看见对应的情况也是8.
除了通过退出信息来获取退出码和退出信号还可以通过C语言库中的宏来取出退出信号和退出码。
在这里插入图片描述
我们只需要通过取出退出信息,用宏来计算退出信号和退出码即可。
我们来说说waitpid的第三个参数options,第三个参数options表示的是等待时父进程的状态,是阻塞等待还是非阻塞等待,意思就是是一直等待,等子进程结束之后再完成父进程的任务,还是边等待边完成自己的任务。
options的参数:

  1. 0表示阻塞等待
  2. WNOHANG表示非阻塞等待
    非阻塞等待状态样例代码:
#include<iostream>
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
int main()
{pid_t id = fork();if(id == 0)//child{int count=5;while(count--){cout<<"我是子进程"<<",我的pid是"<<getpid()<<endl;sleep(1);}exit(1);}while(true){int status = 0;pid_t rid =waitpid(-1,&status,WNOHANG);if(rid>0){cout<<"wait success"<<endl;break;}else if(rid<0){cout<<"wait fail"<<endl;cout<<"exit code:"<<((status>>8)&0xFF)<<" exit Signal:"<<(status&0x7F);break;}else//parent do {cout<<"我是父进程,我的pid是"<<getpid()<<endl;sleep(1);}}return 0;
}

可以看见当等待状态为分阻塞时,我们的父子进程都是正常运行的。
在这里插入图片描述

总结

在本篇博客中,我们深入探讨了Linux进程控制的核心概念,从进程的创建、状态管理到终止及等待机制。通过了解 fork、exec 和 wait 等系统调用,我们掌握了如何有效地管理进程的生命周期。此外,我们还分析了父子进程之间的关系以及信号处理在进程控制中的重要性。

掌握进程控制不仅有助于提升对Linux操作系统的理解,更是编写高效和可靠程序的基础。随着对多进程编程的深入掌握,开发者可以更好地利用系统资源,提高应用的性能和响应能力。

希望这篇博客能为您在Linux进程控制的学习旅程中提供有价值的参考和启示。继续探索这一领域,您将发现更多精彩的技术与实践!

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【java】对象的内存存储

目录 对象在内存中的分配设计到的内存结构(理论)类中对象的内存解析创建类的一个对象&#xff0c;属性赋值创建类的多个对象&#xff0c;属性赋值 对象在内存中的分配设计到的内存结构(理论) 栈&#xff1a;方法内定义的变量&#xff0c;存储在栈中 堆&#xff1a;new出来的结…

【wrl2stl】WRL文件转STL文件-Python

之前有一篇博客写了Avizo自动化批量导出wrl文件&#xff1a;【Avizo&Python】离散颗粒的分割、网格化与单颗粒批量自动保存wrl文件_avizo python-CSDN博客 还有一篇写了wrl转为xyz格式文件&#xff1a; Wrl文件转XYZ文件-Python_python 打开wrl三维模型-CSDN博客 在这篇…

【Linux系统编程】第三十九弹---探索信号处理的奥秘:阻塞信号与sigset_t的深入剖析及实战

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、信号处理 2、阻塞信号 2.1、信号其他相关常见概念 2.2、在内核中的表示 2.3、sigset_t 2.4、信号集操作函数 3、完整…

零基础Apifox测试FastAPI接口入门

文章目录 一、FastAPI部分二、Apifox部分1、安装Apifox2、创建接口3、更改测试环境4、发送请求 一、FastAPI部分 python使用fastapi编写接口内容&#xff08;文件名&#xff1a;text.py&#xff09;&#xff1a; from fastapi import FastAPI import uvicornapp FastAPI()ap…

Linux终端退出程序后,TCP地址仍被占用

报错如下&#xff1a; Error on binding: Address already in use 这是一个正在运行的服务器&#xff0c;运行在linux的终端。上一次我使用CtrlZ退出这个程序&#xff0c;再次./my_server想运行这个程序时&#xff0c;出现这个报错。这是由两点原因&#xff1a; 1、守护进程或…

嵌入式通信协议:IIC简明学习笔记

IIC学习笔记 IIC特点 1.适合 小数据场合使用&#xff0c;传输距离短。 2.只能有一个主机。 3.标准IIC速度为100kHZ&#xff0c;高速IIC一般可达400kHZ以上。 4.SCL和SDA都需要接上拉电阻&#xff08;大小由速度和容性负载决定&#xff0c;一般在3.3k-10k之间&#xff09;。 5…

基于anaconda的python3.6安装opencv4.1.15

opencv-python一些新版本由于部分函数涉及专利问题&#xff0c;如sift和surf&#xff0c;有些功能不能很好地被使用&#xff0c;所以最好使用opencv-python 3.4.1.15版本的。 下载地址分别为&#xff1a; 1、https://pypi.tuna.tsinghua.edu.cn/simple/opencv-python/ 查找…

【自制操作系统】0x01MBR

环境 ubuntu 20.04 gcc 9.4.0&#xff08;加载硬盘程序之前都是&#xff0c;最后可能会切换到 gcc 4.4&#xff09; bochs 2.7 bochs 配置 bochs 安装之前文章记录过&#xff0c;现在记录一下本次使用的bochs配置 bochsrc #第一步&#xff0c;首先设置 Bochs 在运行过程中…

SpringBoot接入星火认知大模型

文章目录 准备工作整体思路接入大模型服务端和大模型连接客户端和服务端的连接测试 准备工作 到讯飞星火大模型上根据官方的提示申请tokens 申请成功后可以获得对应的secret&#xff0c;key还有之前创建的应用的appId&#xff0c;这些就是我们要用到的信息 搭建项目 整体思…

ssm056基于Java语言校园快递代取系统的设计与实现+jsp(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 题目&#xff1a;校园快递代取系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本校园快递代取系统…

简单语音信号识别的MATLAB仿真

简单语音信号识别的MATLAB仿真 摘要&#xff1a; 隐马尔可夫模型&#xff08;HMM&#xff09;作为描述语音信号的一种统计模型&#xff0c;在现代语音处理中获得了广泛应用。本文概述了基于HMM的语音识别技术&#xff0c;阐述了预处理&#xff0c;特征提取以及训练&#xff0c…

童年玩具:两款线绳陀螺

1,2图是过去用来安装明线电线的瓷夹。现在应该找不到了。过去安装电线后&#xff0c;家里留下了一些&#xff0c;拿来做线陀螺非常好。 因为它非常重&#xff0c;旋转起来很有力&#xff0c;那声音呼呼响。 3,4图是现在都能看到的一个圆木片&#xff0c;两个孔&#xff0c;穿绳…

AntFlow一款开源免费且自主可控的仿钉钉工作流引擎

在现代企业管理中&#xff0c;流程审批的高效性直接影响到工作的流畅度与生产力。最近&#xff0c;我发现了一个非常有趣的项目——AntFlow。这个项目不仅提供了一个灵活且可定制的工作流平台&#xff0c;还能让用户以可视化的方式创建和管理审批流程。 如果你寻找一个快速集成…

光纤资源APP开发及二次开发说明

光纤资源APP主要由以下几部分组成&#xff1a; 登录界面选择项目界面地图创建节点界面填写详细信息界面成端及端口表界面接续及接续表界面 其中1、2、4界面不需要涉及到ht&#xff0c;故用原生界面即可实现&#xff0c;但是3、5、6涉及到ht&#xff0c;而ht在app中是不兼容的…

鉴源实验室·如何通过雷达攻击自动驾驶汽车-针对点云识别模型的对抗性攻击的科普

01 引 言 随着自动驾驶技术的迅速发展&#xff0c;雷达和激光雷达等传感器在自动驾驶汽车中的作用愈发重要。它们能够生成3D点云数据&#xff0c;帮助车辆实时感知周围环境并做出安全决策。然而&#xff0c;尽管这些传感器对驾驶环境的检测非常精确&#xff0c;它们也面临一种…

Stable Diffusion(2024)Ai绘画AIGC最新安装包资源下载+自学教程

以下内容为整理的Stable Diffusion保姆级教学内容&#xff0c;请购买的资料的同学务必认真学习&#xff01;按以下步骤操作快速掌握Stable Diffusion这个工具&#xff01; Stable Diffusion&#xff08;简称SD&#xff09;是一款地表最强AI绘图工具(AIGC)之一&#xff0c;Stab…

基于单片机的宠物自动喂食系统的设计

本设计以STM32单片机为核心控制器&#xff0c;搭载了OLED显示屏作为显示交互模块&#xff0c;HX711称重模块获取食物重量&#xff0c;ESP8266与手机APP通信从而远程控制&#xff0c;PWM输出控制舵机模拟投喂食物开关打开&#xff0c;驱动继电器控制水泵打开加水&#xff0c;HC-…

vue+websocket实现即时聊天平台

目录 1 什么是websocket 2 实现步骤 2.1 导入依赖 2.2 编写代码 1 什么是websocket WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它主要用于在客户端和服务器之间建立持久的连接&#xff0c;允许实时数据交换。WebSocket 的设计目的是为了提高 Web 应用程序的…

Spring Boot框架:大学城水电管理自动化

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

关于三色标记算法的理解

三色标记算法是一种垃圾标记的算法&#xff0c;用于cms和g1。 它将对象分为3种颜色&#xff1a; 1.白色对象&#xff1a;未被标记的对象 2.灰色对象&#xff1a;自身被标记&#xff0c;引用的其它对象还没被标记 3.黑色对象&#xff1a;自身以及所引用的对象都被标记完 标记过…