Linux操作系统——进程控制(一) 进程创建和进程终止

news2024/11/18 19:55:48

进程创建

fork函数

在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。

#include <unistd.h>
pid_t fork(void);
返回值:自进程中返回0,父进程返回子进程id,出错返回-1

进程调用fork,当控制转移到内核中的fork代码后,内核做:

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

当一个进程调用fork之后,就有两个二进制代码相同的进程。而且它们都运行到相同的地方。但每个进程都将可以开始它们自己的旅程,看如下程序。

int main( void )
{
    pid_t pid;
    printf("Before: pid is %d\n", getpid());
    if ( (pid=fork()) == -1 )perror("fork()"),exit(1);
    printf("After:pid is %d, fork return %d\n", getpid(), pid);
    sleep(1);
    return 0;
}
运行结果:
[root@localhost linux]# ./a.out
Before: pid is 43676
After:pid is 43676, fork return 43677
After:pid is 43677, fork return 0

这里看到了三行输出,一行before,两行after。进程43676先打印before消息,然后它有打印after。另一个after消息有43677打印的。注意到进程43677没有打印before,为什么呢?如下图所示:

所以,fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器决定。

fork函数返回值

  • 子进程返回0,
  • 父进程返回的是子进程的pid。

写时拷贝

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

当父进程创建子进程之后,子进程进行写入,会发生写时拷贝?重新申请空间,进行拷贝,修改页表,这部分工作都是由操作系统来做的。那么我想请问一下,你说发生写时拷贝就发生写时拷贝啊?你当前可是在发生写入啊,那么操作系统是怎么把握这个时机来完成写时拷贝的这个工作呢?

比如说你在家的时候,你说你饿了,你爸还没下班,你就准备动筷子吃饭了,你妈这个时候刚好叫住你说:"等一下,我先给你把打包一份你在吃",打包之后就说:"好了,现在你可以吃了。"就好比这样,但是呢,操作系统到底如何能做到什么时机应该完成写时拷贝呢?

其实,父进程创建子进程的时候首先把自己的读写权限改成只读,然后再创建子进程。这个工作我们作为用户是不知道的,那么用户就可能对某一批数据进行写入!而写入的时候由于权限是只读的,那么在我们的页表转换会因为权限问题而出错,一旦出错了,操作系统就可以介入了。出错的原因可能是真的出错了,也有可能不是出错,而是触发我们进行重新申请内存拷贝内容的策略机制。(写时拷贝)

fork常规用法

  • 一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
  • 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。

fork调用失败的原因

  • 系统中有太多的进程
  • 实际用户的进程数超过了限制

下面我们通过写一份多进程的代码:

运行结果:

进程终止

我们平常写的C语言代码都有一个main函数,而这个main函数有一个返回值,我们通常返回的是0,那么我们main函数也是函数,所以它也会被调用,那么main函数是被谁调用呢?这个0又是给谁进行返回呢?

那我们下面来谈一谈main函数的 返回值。

其实我们的main函数一般是被一个__StartCRT的函数给调用了,既然被调用了那么这个main函数返回值应该就是交给调用他的函数,其实调用他的函数也要将返回值继续向上进行传递。为什么呢?

下面我们先把main函数退出码设为10.

我们运行起来

当前代码什么工作都没做,但是这个可执行程序一运行起来变成一个进程,变成进程之后他的父进程就是bash,而这个进程的main函数的返回值最终会交给父进程。

下面我们通过该指令获取一些父进程收到的退出结果。

我们就得到了一个退出结果是10,这个退出结果就是刚刚main函数的返回结果。

这是我们发现的一个现象。

其实在我们的生活中平常做的事情的情况来分,你做任何一件事情情况无外乎就这三种:

  • 事情做完了,做的做的结果非常好。
  • 事情做完了,做的结果很不好。
  • 事情没做完,中间出问题出岔子。

比如说我们平常考试,第一,你把试考完了,但是考出来的结果不太好,第二种,你把试考完了,考出来的结果非常好,第三种,你考试没考完,中间出岔子了,比如说作弊被抓了,没考完。

同样在我们的程序当中也是从这个三种情况来看的:

  • 代码运行完毕,结果正确
  • 代码运行完毕,结果不正确
  • 代码异常终止

举个简单例子,我们在跑一个冒泡排序的代码的时候,要么就是代码跑完了,最后排出来的结果是正确的,要么呢就是代码跑完了跑出来的结果不正确,还有一种呢就是跑到一般代码出异常了。

我们上面所谈的main函数的返回值目前只考虑前两种情况,也就是把代码异常终止的情况排除在外。我们代码运行完毕结果不正确还是结果正确,我们得知道这个结果。那么这里说的我们指的是谁呢?如果我们写了一个单进程的代码,比如说链表逆置的算法,或者一个什么算法最终的结果是需要我们自己去看的,如果我们在多进程环境中,我们创建子进程的最终目的是什么?最终目的是帮我办事。子进程把事情办得怎么样呢?这里的我们一般都是指的父进程。而我们的子进程把事情办得怎么样了是通过main函数的返回值来进行识别的,比如说返回值是0那就说明办成功了,而非0代表出错了,但是出错的原因有很多啊,具体是由于什么原因出错的,非0的数字有很多,0只有一个,这个时候就是通过不同的数字来代表不同的出错的原因的。但是呢一般用这些纯数字来表示出错原因对于人来讲不便于人阅读,所以就有了将exit code-> exit code string! 也就是将对应的退出码转换成人便于阅读的字符串,其实c语言内置的一个函数接口:

其实我们一开始学习的时候也不知道怎么来描述的,所以我们通过一段代码来进行测试:

运行结果:

上述的错误码就是我们可能出现的错误信息与错误码之间的对应关系。

我们发现到了134之后就是都不认识了。

根据不同的结果现象,返回不同的退出码,什么现象?

C语言有一个全局变量叫errno是C语言的错误码。我们来看一下errno的说明:

退出码vs错误码

错误码通常是用来衡量一个库函数或者是一个系统调用一个函数的调用情况

退出码通常是一个进程退出的时候,他的退出结果。

虽然这两个是不同的概念,但是他们都有共同的表征,那就是当失败的时候,用来衡量函数,进程出错时的详细出错原因。

下面我们编写如下代码将错误信息打印出来:

运行结果:

下面呢我们再从代码异常终止的情况来了解异常问题:

 下面我们用除0错误和野指针问题来进行说明:

运行结果:

我们可以看到出现了除0错误。

下面再用一个野指针问题

运行结果:

野指针问题,在Linux中叫做段错误。

如果我们的程序异常了,本质就是我们的进程异常了,进程出异常了,我们的操作系统为了不让该进程影响到别人通常会将这个异常的进程给杀掉,那么怎么杀掉呢?通过信号的方式:

我们刚刚的除0异常其实就是上图中的8号信号,而我们的段错误是上图中的11号信号。

上述我们说到的进程异常终止其实是因为进程收到了操作系统发送的信号导致的异常终止的,那么怎么证明呢?

下面我们通过运行这段代码

运行起来之后为了验证操作系统是通过发送信号让进程异常终止的同时报错异常终止的原因,那么我们是不是也可以通过发送信号让一个正常运行的进程报出相对应的错误呢?

我们再另一个窗口上发送了一个8号信号发现确实报错浮点数除零错误,发送了一个11号信号发现确实报错段错误。

所以我们就得出了一个结论:进程出异常,本质是进程收到了相对应的信号,进程终止了。

所以一个进程是否异常我们只要看有没有收到信号即可,而判断一个进程运行是否正确只需要通过进程的退出码来判断。所以父进程本质只需要关注这两个数字来判断子进程完成的任务如何。

进程常见退出方法

1.从main函数返回

首先我们可以看一下这一段代码:

我们运行一下:

发现最近一个进程的退出码就是main函数中return的值,所以这是一种进程退出的方法。

2.调用exit

我们先看看exit的手册:

exit()是c提供的一个接口,这个exit 中有一个参数,所以我们可以很容易的想到这个参数就是我们进程的退出码。

此时为了验证该函数是用来进行进程退出的,我们可以直接用以下代码进行测试:

运行结果:

我们发现进程的退出码是12,所以exit中的参数是进程的退出码,等价于main函数中的return.

下面我们把代码改成如下情况:

然后再运行之后:

第一个现象:fun函数被调用了,后续代码没有跑了。

第二个现象:当前退出码变成了21了,而不是12了。

所以我们得出了结论:任意地点调用exit表示进程退出,不进行后续执行。

为了进一步验证该结论我们可以再尝试一次代码的验证:

然后运行:

我们发现这个程序啥都没干就退出了,然后进程退出码变成了31.

所以后续我们想让一个进程直接退出的时候我们就可以直接调用exit();

3._exit

_exit的手册:

下面我们把我们上述写到的代码中的exit 换成_exit

进行运行:

发现跟exit的结果是一样的,其实在这里与exit的效果一样。

下面我们来讨论这两者有什么区别呢?

首先我们先对exit来进行操作:

然后运行:

这条打印的消息会先刷出来然后再暂停3s然后退出。

如果把\n去掉,也就是不让他刷新缓存区:

代码变成这样然后运行:

刚开始是这样

然后:

这样是在进程退出的时候是会自动刷新缓存区的。

如果我们换成_exit的话:

运行是这样:

这是通过行刷新来刷新缓冲区的,所以没有问题,但是如果我们把\n去掉之后运行:

运行之后:

发现打印消息直接不见了。

两者区别:

1.exit是库函数,_exit是系统调用。

2.exit终止进程的时候,会自动刷新缓冲区。_exit终止进程的时候不会自动刷新缓冲区。

我们目前知道的缓冲区,绝对不在操作系统内部。

不然的话双方都应该刷新。

我们把关于缓冲区这个问题留到后面。

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

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

相关文章

数据分析-25-电商用户行为可视化分析

文章目录 0. 数据代码获取1. 项目介绍1.1 分析背景1.2 分析目的1.3 分析思路 2. 数据清洗2.1 加载必要的库2.2 读取数据2.3 统计缺失值2.4 处理数据a. 删除重复值b. 转换时间格式c. 提取日期和时间d. 转换数据类型 3. 分析内容3.1 用户活跃规律a. 日均pv与uvb. 日新增pv、uv趋势…

使用echarts制作柱状图并且下方带表格

实现效果: 调试地址: Examples - Apache ECharts 源码: option { title: { left: center, top: 0, text: 2022-05月 制造产量 达成情况(单位: 吨) (图1)\n\n集团目标产量: 106,675吨 集团实际产量: 2,636吨, textStyle:{ fontSize:20, colo…

React 入门 - 01

本章内容 目录 1. 简介1.1 初始 React1.2 React 相关技术点1.3 React.js vs Vue.js 2. React 开发环境准备2.1 关于脚手架工具2.2 create-react-app 构建一个 React 项目工程 1. 简介 1.1 初始 React React JS 是 Facebook 在 2013年5月开源的一款前端框架&#xff0c;其带来…

【UML建模】部署图(Deployment Diagram)

1.概述 部署图是一种结构图&#xff0c;用于描述软件系统在不同计算机硬件或设备上的部署和配置情况&#xff0c;以图形化的方式展示系统中组件、节点和连接之间的物理部署关系。 通过部署图&#xff0c;可以清晰地了解系统的物理结构和部署方式&#xff0c;包括系统组件和节…

小程序购物商城搭建开发分析

小程序商城作为现代商业模式的重要组成部分&#xff0c;具有巨大的发展潜力和商业价值。通过搭建一个功能完善、用户友好的小程序商城&#xff0c;您将能够提供便捷的购物体验&#xff0c;吸引更多的用户并实现商业增长。在进行小程序商城开发搭建之前&#xff0c;我们需要对项…

期末成绩这样发 老师省心 家长舒心

从很久以前开始就不能公布学生的分数了&#xff0c;很多学校都是只公布等级或者是大概的范围&#xff0c;那么如何合理告知家长成绩呢&#xff1f; 在家长群内发布公告&#xff0c;告知考试成绩已经出炉&#xff0c;如果家长需要了解具体分数&#xff0c;可以私信联系你。这样既…

网络割接为什么经常是半夜进行?

你们好&#xff0c;我的网工朋友。 假设你最近遇到了一个客户&#xff0c;客户有个新的园区刚刚建成&#xff0c;园区内包括建筑物若干&#xff0c;地理覆盖面也较广&#xff0c;园区建成后&#xff0c;肯定是需要一个专用网络的&#xff0c;用于承载公司的业务流量。 这时候&…

C语言编译器(C语言编程软件)完全攻略(第五部分:VS2015使用教程(使用VS2015编写C语言程序))

介绍常用C语言编译器的安装、配置和使用。 五、VS2015使用教程&#xff08;使用VS2015编写C语言程序&#xff09; 前面我们给出了一段完整的C语言代码&#xff0c;就是在显示器上输出“C语言中文网”&#xff0c;如下所示&#xff1a; #include <stdio.h> int main() {…

网页爬虫在数据分析中的作用,代理IP知识科普

在当今信息爆炸的时代&#xff0c;数据分析成为洞察信息和制定决策的不可或缺的工具。而网页爬虫&#xff0c;作为数据收集的得力助手&#xff0c;在数据分析中扮演着举足轻重的角色。今天&#xff0c;我们将一同探讨网页爬虫在数据分析中的作用。 1. 数据收集的先锋 网页爬虫…

【AWS系列】巧用 G5g 畅游Android流媒体游戏

序言 Amazon EC2 G5g 实例由 AWS Graviton2 处理器提供支持&#xff0c;并配备 NVIDIA T4G Tensor Core GPU&#xff0c;可为 Android 游戏流媒体等图形工作负载提供 Amazon EC2 中最佳的性价比。它们是第一个具有 GPU 加速功能的基于 Arm 的实例。 借助 G5g 实例&#xff0c;游…

OAI openair3代码结构整理

openair3代码框架结构 OAI&#xff08;OpenAirInterface&#xff09;是一个开源的5G网络软件平台&#xff0c;用于研究和开发5G网络技术。OpenAir3是OAI项目中的一个子项目&#xff0c;专注于5G核心网络的功能实现。 一、OpenAir3的代码主要包括以下几个部分&#xff1a; NAS…

如何使用loki查询日志中大于某一数字的值的日志

简介 loki是一款轻量级的日志收集中间件&#xff0c;比elk体系占用的内存更小&#xff0c;采用go语言开发&#xff0c;可以利用grafana来查询loki中存储的日志&#xff0c;loki存储日志只对提前预设的标签做索引&#xff0c;所以日志存储空间占用比elk小很多。 方法 loki只对…

Springboot整合RocketMQ 基本消息处理

目录 1. 同步消息 2. 异步消息 3. 单向消息 4. 延迟消息 5. 批量消息 6. 顺序消息 7. Tag过滤 导入依赖 <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId></dependency> …

如何使用可视化管理工具DockerUI远程管理docker容器

文章目录 前言1. 安装部署DockerUI2. 安装cpolar内网穿透3. 配置DockerUI公网访问地址4. 公网远程访问DockerUI5. 固定DockerUI公网地址 前言 DockerUI是一个docker容器镜像的可视化图形化管理工具。DockerUI可以用来轻松构建、管理和维护docker环境。它是完全开源且免费的。基…

准博士生教你如何阅读论文

AI方向如何阅读论文 绪论会议整理一篇论文的主要结构AbstractIntroductionRelated WorkApproach(framework名称亦可)ExperimentsImplementation detailsResultsAblation StudyDiscussion Conclusion 如何阅读多篇论文怎样读/写related work怎样读approach结语 绪论 作为一位工…

SSM在线手机品牌商城----计算机毕业设计

项目介绍 该项目为前后台项目&#xff0c;分为普通用户与管理员两种角色&#xff0c;前台普通用户登录&#xff0c;后台管理员登录&#xff1b; 管理员角色包含以下功能&#xff1a; 管理员登录,用户管理,品牌管理,子品牌管理,商品管理,订单管理,留言板管理等功能。 用户角…

华为交换机ETH-TRUNK链路聚合lacp模式与手工模式

SW1配置如下 vlan batch 10interface Eth-Trunk1port link-type trunkport trunk allow-pass vlan 10mode lacp-static #手工模式删除改行max active-linknumber 2 #手工模式删除改行trunkport GigabitEthernet 0/0/1 to 0/0/2#配置为主设备&#xff08;修改优先级&…

DevOps(8)

目录 36.当发出的命令与上次使用时产生的结果不同时&#xff0c;会出现什么问题&#xff1f; 37./usr /local的内容是什么&#xff1f; 38.你如何终止正在进行的流程&#xff1f; 39.如何在命令行提示符中插入注释&#xff1f; 40.什么是命令分组以及他是如何工作的&…

效果图渲染角度哪什么小技巧?

在创建效果图渲染时&#xff0c;正确设置相机角度对于表现设计的视觉效果至关重要。好的效果图通常能够增强设计图张力&#xff0c;通过效果图也能更好的看到真实物体的成果&#xff0c;以下是一些效果图渲染角度技巧&#xff0c;可以帮助你提高渲染的质量和表现力&#xff0c;…

odoo16 产品变体之体验

odoo16 产品变体之体验 最近接一个服装批发公司的业务,初步使用了一下产品变体功能,真的太棒了,记录一下使用的效果与注意事项,有此类需求或正在做此类功能的可以一块交流。 产品变体: 产品变体,做过服装类行业的程序员都知道,一个款式的衣服上市,通常会有好多种颜色…