我与Linux的爱恋:进程创建|终止

news2024/11/20 9:44:45


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

🔥个人主页guoguoqiang. 🔥专栏Linux的学习

Alt


文章目录

  • 一、进程创建
    • **fork函数**
    • 写时拷贝
  • 二、进程终止
    • 进程退出的常见方法

一、进程创建

fork函数

在Linux中fork函数是非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,原进程为父进程,其中返回值:子进程中返回0,父进程返回子进程id,出错返回-1;
在这里插入图片描述

测试

#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h> 
int main()
{
        printf("before fork, pid = %d\n", getpid());
        pid_t id = fork();
        assert(id != -1);//进程创建失败
        (void)id;
 
        printf("after fork, pid = %d, fork return %d\n", getpid(), id);
        return 0;
}

在这里插入图片描述
上面代码执行路径如下图所示
在这里插入图片描述
进程调用fork,当控制转移到内核中的fork代码后,内核做:

  • 分配新的内存块和内核数据结构给子进程
  • 将父进程部分数据结构内容拷贝至子进程
  • 添加子进程到系统进程列表当中
  • fork返回,开始调度器调度

在这里插入图片描述

当父进程调用fork时,会发生:
1.进程复制: 操作系统会创建父进程的一个副本,这个副本就是子进程。子进程几乎和父进程完全相同。
2.资源共享与复制 子进程与父进程有区别 ,例如 他们有不同的进程ID(PID).不同的父进程ID(PID)以及一些独立的资源,如虚拟内存等。
3.执行流程:fork() 调用之后,父进程和子进程都会从 fork() 函数调用后的下一条指令开始执行。
4.返回值:fork() 在父进程中返回子进程的 PID,在子进程中返回 0,如果出错则返回 -1。
fork的常规用法
一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如:父进程等待请求,子进程执行请求。
一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。
fork调用失败的原因:
系统中有太多的进程
实际用户的进程超过了限制

写时拷贝

写时拷贝(Copy-on-Write,COW)是一种优化技术,主要用于管理内存和资源,尤其在操作系统和数据库系统中广泛应用。

通常,父子代码共享,父子再不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本。

工作原理
1.初始状态:

当一个对象或数据被复制时,系统并不立即创建一个新的实例,而是创建一个指向原始数据的引用或指针。
2.共享数据:

多个对象或进程可以共享同一份数据,直到其中一个对象需要修改数据。
3.数据修改:

当某个对象尝试修改共享数据时,系统会将这份数据进行拷贝,创建一个独立于原始数据的新实例。
只有修改的数据被拷贝,而其他未被修改的部分仍然与原始数据共享,这样可以节省内存和提高效率。
4.独立性:

修改后的对象不再共享原始数据的引用,而是独立于其他对象,从而确保数据的一致性。

优点
1.内存效率:

由于不立即复制数据,减少了不必要的内存使用,可以更有效地管理系统资源。
2.性能提升:

在大多数情况下,降低了复制开销,尤其是在频繁创建和销毁对象的场景中。
3.线程安全:

每个线程或进程在写入时都拥有自己的数据副本,避免了多线程环境中潜在的数据竞争和冲突问题。
4.简化回滚操作:

在某些应用中,如数据库或版本控制系统,可以容易地回滚到之前的状态,因为未修改的部分仍然共享原始数据。

缺点
1.延迟开销:

在第一次写入时,由于涉及数据拷贝,可能会造成性能的延迟,这在某些实时系统中是不可接受的。
2.增加复杂性:

管理指针和引用关系可能增加系统的复杂性,尤其在需要频繁检查和操作这些引用时。
3.内存碎片:

在频繁拷贝和修改的情况下,可能导致内存碎片化,影响系统的整体性能。
4.不足以处理大数据:

在处理非常大的数据集时,COW可能会导致过多的拷贝和高内存占用,这会抵消其初衷。
在这里插入图片描述

二、进程终止

想一下进程终止是什么?
操作系统要释放进程申请的相关内核数据结构和对应的数据和代码(本质就是释放系统资源)。
进程退出场景

  • 代码执行完毕,结果正确
#include <stdio.h>
int Add(int begin,int end){
    int sum=0;
    for(int i=begin;i<=end;i++){
        sum+=i;
    }
    return sum;
}
int main(){
    printf("Add 1 to 100 is %d\n",Add(0,100));
    return 0;
}

在这里插入图片描述

  • 代码运行完毕,结果不正确
#include <stdio.h>
int Add(int begin,int end){
    int sum=0;
    for(int i=begin;i<end;i++){
        sum+=i;
    }
    return sum;
}
int main(){
    printf("Add 1 to 100 is %d\n",Add(0,100));
    return 0;
}

在这里插入图片描述

  • 代码异常终止。代码没跑完,程序崩溃
#include <stdio.h>
int main(){
    int *p=NULL;
    *p=100;//野指针解引用
    return 0;
}

在这里插入图片描述
在我们写代码时程序运行结束时我们会用return语句返回一个数作为main的返回值,这个返回值有什么用呢?
例子:
在我们考试后,家长问成绩,如果考的好,就不会说什么,考的不好则需要说明原因。
我们做出下列约定:

数字代表的原因
1考试过程中生病了
2考试的时候着急了
在操作系统中,当程序正常运行时我们不说什么,(正常程序运行终止返回状态码0),但程序一旦出现错误(返回码非0),我们就需要知道出错的原因。操作系统对于不同的状态码给了不同的错误描述信息,我们可以使用errno.h 下的 errno 变量获取错误码,使用 strerror(errno)获取错误码的错误描述。
#include <stdio.h>
#include <string.h>
 
int main()
{
	for(int i = 0; i < 400; i++)
	{
		printf("[%d]->%s\n", i, strerror(i));
	}
	return 0;
}

在这里插入图片描述
父进程会关心子进程的退出码

父进程关心子进程的退出码(即退出状态)主要是出于以下几个原因:

  1. 了解子进程的执行结果
    退出码通常表示子进程的执行状态,父进程可以通过这个码判断子进程是成功结束(通常为0)还是发生了错误(非0值)。这对于调试和错误处理非常重要。
  2. 后续处理
    在一些场景中,父进程根据子进程的执行结果来决定后续的操作。例如,如果子进程成功执行,父进程可能会继续进行相关工作;如果失败,父进程可能需要采取补救措施或终止工作。
  3. 资源管理
    子进程的退出会影响系统的资源管理。父进程需要调用相应的系统调用(如 wait 或 waitpid)来收集子进程的退出状态,防止出现僵尸进程(Zombie Process),即那些已经结束但父进程未处理其状态的进程。
  4. 同步与协调
    在多进程环境中,父进程需要对子进程的状态进行监控,以实现进程间的同步。这对于协调多个进程的工作、确保程序的正常运行很重要。
  5. 日志和审计
    在某些情况下,父进程可能需要记录子进程的退出状态,以便后期进行审计和分析。这在系统监控和故障排查中会有所帮助。

在这里插入图片描述
第一个139 表示程序出现了Segmentation fault错误
而第二个零表示echo $?成功

一旦程序出现异常,退出码就没意义了
我们可以看进程退出的时候,退出信号是多少,就可以判断进程为什么异常了。

进程出异常本质是因为进程收到了OS发给进程的信号

在该程序发生错误时,操作系统给该程序的进程发送了8号信号SIGFPE。我们可以通过 kill -l 查看所有的信号码以及对应信号名
在这里插入图片描述
我们来验证一下,上面的程序是通过接收到8号信号才结束的
在这里插入图片描述
在这里插入图片描述

SIGHUP 1 A 终端挂起或者控制进程终止

SIGINT 2 A 键盘中断(如break键被按下)

SIGQUIT 3 C 键盘的退出键被按下

SIGILL 4 C 非法指令

SIGABRT 6 C 由abort(3)发出的退出指令

SIGFPE 8 C 浮点异常

SIGKILL 9 AEF Kill信号

SIGSEGV 11 C 无效的内存引用

SIGPIPE 13 A 管道破裂: 写一个没有读端口的管道

SIGALRM 14 A 由alarm(2)发出的信号

SIGTERM 15 A 终止信号

SIGUSR1 30,10,16 A 用户自定义信号1

SIGUSR2 31,12,17 A 用户自定义信号2

SIGCHLD 20,17,18 B 子进程结束信号

SIGCONT 19,18,25 进程继续(曾被停止的进程)

SIGSTOP 17,19,23 DEF 终止进程

SIGTSTP 18,20,24 D 控制终端(tty)上按下停止键

SIGTTIN 21,21,26 D 后台进程企图从控制终端读

SIGTTOU 22,22,27 D 后台进程企图从控制终端写

处理动作一项中的字母含义如下

A 缺省的动作是终止进程

B 缺省的动作是忽略此信号,将该信号丢弃,不做处理

C 缺省的动作是终止进程并进行内核映像转储(dump core),内核映像转储是指将进程数据在内存的映像和进程在内核结构中的部分内容以一定格式转储到文件系统,并且进程退出执行,这样做的好处是为程序员提供了方便,使得他们可以得到进程当时执行时的数据值,允许他们确定转储的原因,并且可以调试他们的程序。

D 缺省的动作是停止进程,进入停止状况以后还能重新进行下去,一般是在调试的过程中(例如ptrace系统调用)

E 信号不能被捕获

F 信号不能被忽略

进程退出的常见方法

正常终止与异常终止
正常终止(可以通过echo $?查看进程退出码)

  1. 从main函数返回
  2. 调用exit
  3. _exit
    异常终止
    ctrl + c 信号终止
    exit与_exit的区别
    终止处理程序和I/O缓冲区:exit()会执行终止处理程序和I/O缓冲区的清理,而_exit()则不会。

头文件:exit()在stdlib.h中定义,而_exit()在unistd.h中定义。

_exit()不会进行清理工作。

#include <stdio.h>
#include <unistd.h>
 
int main()
{
        printf("1 + 1 = %d", 1 + 1);
        _exit(1);
        return 0;
}

在这里插入图片描述
我们发现没有打印出1+1的结果,也就是_exit不会刷新缓冲区
如果换成exit
在这里插入图片描述
exit最后也会调用exit, 但在调用exit之前,还做了其他工作:

  1. 执行用户通过 atexit或on_exit定义的清理函数。
  2. 关闭所有打开的流,所有的缓存数据均被写入
  3. 调用_exit

return退出

return是一种更常见的退出进程方法。执行return n 等同于执行exit(n),因为调用main的运行时函数会将main的返回值当作exit的参数

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

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

相关文章

黑马智数Day4-2

渲染基础Table列表 封装获取企业列表接口 export function getEnterpriseListAPI(params) {return request({url: /park/enterprise,params}) } 组件中获取数据 <script> import { getEnterpriseListAPI } from /apis/enterprise export default {name: Building,dat…

C++ | Leetcode C++题解之第435题无重叠区间

题目&#xff1a; 题解&#xff1a; class Solution { public:int eraseOverlapIntervals(vector<vector<int>>& intervals) {if (intervals.empty()) {return 0;}sort(intervals.begin(), intervals.end(), [](const auto& u, const auto& v) {retur…

直播平台美颜功能开发方案:基于视频美颜SDK的集成详解

本篇文章&#xff0c;小编将于大家共同探究视频美颜SDK的美颜功能开发方案&#xff0c;帮助开发者深入理解其集成过程及关键技术。 一、美颜功能的重要性 在竞争激烈的直播市场中&#xff0c;直播平台如何提升用户体验至关重要。美颜功能不仅能够改善主播的形象&#xff0c;提…

桌面专业版【查看MAC和ip地址】

UOS统信查看MAC和ip地址的方法。 文章目录 查看方法一、图形化界面查看二、命令查看 查看方法 一、图形化界面查看 打开控制中心-网络-网络详情中-Mac地址就是您电脑的mac地址&#xff0c;IPV4就是您电脑的ip地址。 二、命令查看 桌面右键选择在终端中打开&#xff0c;输入i…

9.25度小满一面

1.map的底层 2.unorder_map哈希表有自己实现过吗&#xff1f;哈希冲突 3.poll和epoll和select的优缺点、 4.线程同步机制是用来做什么的? 5.五子棋项目问题-- 算法题: 6.LeetCode.重排链表 给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0…

Linux:地址分区——常量区、全局区、堆区、栈区

平台&#xff1a;Linux。本次实验是基于Linux平台&#xff0c;结论和其他平台大体相同&#xff0c;如有出入&#xff0c;也属于正常现象。实验内容&#xff1a;大致验证地址空间的各个分区。 结论如图&#xff1a; 结论说明&#xff0c;由低地址向高地址&#xff1a; 代码区&a…

Cortex-A7和Cortex-M7架构处理器取中断向量全流程分析

0 参考资料 Cortex M3权威指南(中文).pdf ARM Cortex-A(armV7)编程手册V4.0.pdf1 Cortex-A7和Cortex-M7处理器架构取中断向量全流程分析 1.1 什么是中断向量&#xff1f; 中断向量就是中断服务函数入口地址&#xff0c;例如我们发生了EXTI0中断&#xff0c;就需要执行EXT0中…

JavaScript 基础 - 第22天_Webpack模块打包工具

Day03_Webpack模块打包工具 目录 Webpack 简介与体验案例 - 打包注册用户网页插件 plugins 和加载器 loader 的使用案例 - 注册用户完成 - npm 作用在前端项目Webpack 开发服务器&#xff0c;打包模式调试代码 source map配置 路径 学习目标 了解 Webpack 的作用掌握 npm …

el-table中根据状态改单元格样式

需求&#xff1a;el-table中&#xff0c;有一列需要根据状态不同&#xff0c;显示的样式也不通。 解决方法&#xff1a; :cell-style"cellStyle" <el-table:data"tableData"style"width: 100%"size"mini"border:header-cell-style…

基于大数据可视化的化妆品推荐及数据分析系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

Html--笔记01:使用软件vscode,简介Html5--基础骨架以及标题、段落、图片标签的使用

一.使用VSC--全称&#xff1a;Visual Studio Code vscode用来写html文件&#xff0c;打开文件夹与创建文件夹&#xff1a;①选择文件夹 ②拖拽文件 生成浏览器的html文件的快捷方式&#xff1a; &#xff01;enter 运行代码到网页的方法&#xff1a; 普通方法&#xff1a…

毕业设计选题:基于ssm+vue+uniapp的自助购药小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

进阶SpringBoot之 Dubbo 及 Zookeeper 安装

Dubbo 文档 Dubbo 是一款高性能、轻量级的开源 Java RPC 框架 它提供了三大核心功能&#xff1a; 面向接口的远程方法调用、智能容错和负载平衡、服务自动注册和发现 ZooKeeper 是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是 Hadoop 和 Hbase …

Vue75 编程式路由导航

笔记 作用&#xff1a;不借助<router-link> 实现路由跳转&#xff0c;让路由跳转更加灵活 具体编码&#xff1a; //$router的两个API this.$router.push({name:xiangqing,params:{id:xxx,title:xxx} })this.$router.replace({name:xiangqing,params:{id:xxx,title:xxx} …

K8s flink-operator 例子

1.参考官网&#xff1a; https://nightlies.apache.org/flink/flink-kubernetes-operator-docs-stable/docs/try-flink-kubernetes-operator/quick-start/ 2.首先环境具备 k8s、helm 我的环境 k8s 1.30 最新版本了 [rootk8s-master ~]# kubectl get no -owide NAME …

【QGIS】软件下载安装及GIS4WRF插件使用

【QGIS】软件下载安装及GIS4WRF插件使用 QGIS软件下载软件安装GIS4WRF插件导入参考 QGIS软件下载 官网-QGIS-Spatial without Compromise 下载安装包&#xff0c;居然有1.2G&#xff0c;那就慢慢下载吧&#xff01; 软件安装 双击安装包&#xff0c;如下&#xff1a; 接受…

MATLAB案例 | 沪深股市收益率的二元Copula模型

沪深股市收益率的二元Copula模型 1. 案例描述2.实现流程2.1 确定随机变量的边缘分布2.1.1 参数法计算流程2.1.2 非参数法 2.2 选取适当的Copula函数2.3 参数估计 3. 完整代码参考资料 1. 案例描述 现有上海和深圳股市同时期日开盘价、最高价、最低价、收盘价、收益率等数据,跨…

9.2自适应阈值分割

基本概念 在图像处理中&#xff0c;阈值分割是一种简单而有效的图像分割方法&#xff0c;它根据像素值将图像分割成前景和背景。自适应阈值分割是阈值分割的一种高级形式&#xff0c;它考虑了图像局部区域的亮度变化&#xff0c;从而能够更准确地分割图像。OpenCV是一个强大的…

完全二叉树和堆排序

完全二叉树 完全二叉树满足以下两个条件&#xff1a; 所有层的节点都完全填满&#xff1a;除了最后一层外&#xff0c;每一层的节点数都是最大节点数&#xff0c;即除了最后一层&#xff0c;其他层的节点数都是满的。 最后一层的节点尽可能地向左排列&#xff1a;在满足第一…

调试技巧 conso.trace()

console 的 trace() 方法向 Web 控制台输出一个堆栈跟踪。 trace是一个很好的调试错误的办法&#xff0c; console.trace() 方法用于显示当前执行的代码在堆栈中的调用路径。 可以查看函数在哪一些地方做了调用 这个在找不出变量在何处被修改的时候&#xff0c;很有用 同时…