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

进程创建

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.rhkb.cn/news/231992.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构和算法-交换排序中的冒泡排序(过程 代码实现 算法效率 稳定性 适用链表?)

文章目录 总览冒泡排序冒泡&#xff1f;啥是冒泡排序冒泡排序过程算法实现算法性能分析稳定性冒泡排序是否适用于链表 小结 总览 冒泡排序 冒泡&#xff1f; 自然界的冒泡 啥是冒泡排序 冒泡排序过程 此时序列要求递增的 首先比较27和49&#xff0c;发现符号递增序列&…

【Linux Shell】6. echo 命令

文章目录 【 1. 显示普通字符串 】【 2. 显示转义字符 】【 3. 显示变量 】【 4. 显示换行 】【 5. 显示不换行 】【 6. 显示命令执行结果 】 Shell 的 echo 指令用于字符串的输出。命令格式&#xff1a; echo string【 1. 显示普通字符串 】 #!/bin/bashecho "It is a …

全程云OA ajax.ashx SQL注入漏洞复现

0x01 产品简介 全程云OA为企业提供日常办公管理、公文管理、工作请示、汇报、档案、知识体系、预算控制等26个功能,超过100多个子模块。为企业内部提供高效、畅通的信息渠道,同时也能大力推动公司信息系统发展,提高企业的办公自动化程度和综合管理水平,加快企业信息的流通…

Kubernetes二进制部署 单节点

一、环境准备 k8s集群master1&#xff1a;192.168.229.90 kube-apiserver kube-controller-manager kube-scheduler etcd k8s集群node1: 192.168.229.80 kubelet kube-proxy docker flannel k8s集群node2: 192.168.229.70 kubelet kube-proxy docker flannel 至少2C2G 常见的k…

单片机快速入门

参考连接&#xff1a; 安装MinGW-64&#xff08;在win10上搭建C/C开发环境&#xff09;https://zhuanlan.zhihu.com/p/85429160MinGW-64; 链接&#xff1a;https://pan.baidu.com/s/1oE1FmjyK7aJPnDC8vASmCg?pwdy1mz 提取码&#xff1a;y1mz --来自百度网盘超级会员V7的分享C…

专业级的渗透测试服务,助力航空业数字化安全启航

​某知名航空公司是中国首批民营航空公司之一&#xff0c;运营国内外航线200多条&#xff0c;也是国内民航最高客座率的航空公司之一。在数字化发展中&#xff0c;该航空公司以数据驱动决策&#xff0c;通过精细化管理、数字创新和模式优化等方式&#xff0c;实现了精准营销和个…

Langchain模板-LangChainTemplates 讲解及应用

langchain官方链接&#xff1a;https://github.com/langchain-ai/langchain/tree/master/templates 其他相关链接&#xff1a; https://python.langchain.com/docs/templates https://templates.langchain.com/ Langchain模板&#xff0c;提供一系列的易于部署的参考架构&a…

vmware中ubuntu虚拟机不能够用共享文件夹

有时候发现装好虚拟机后&#xff0c;然后 虚拟机-设置-选项-共享文件夹 然后使用快捷键ctrlaltt 打开命令行&#xff0c;cd /mnt下没有看到hgfs文件夹 解决办法是安装vmware tools工具 此时想通过点击 虚拟机-安装vmwaretools工具 按钮 居然发现该按钮是灰色的&#xff0…

Nginx 多端口部署多站点

目录 1.进行nginx.conf 2.复制粘贴 3.修改端口及站点根目录 4. 网站上传 1.进行nginx.conf 在 nginx 主要配置文件 nginx.conf 中&#xff0c;server 是负责一个网站配置的&#xff0c;我们想要多个端口访问的话&#xff0c;可以复制多个 server 先进入到 nginx.conf 中 …

Elasticsearch:结合 ELSER 和 BM25 文本查询的相关搜索

Elastic Learned Spare EncodeR (ELSER) 允许你执行语义搜索以获得更相关的搜索结果。 然而&#xff0c;有时&#xff0c;将语义搜索结果与常规关键字搜索结果相结合以获得最佳结果会更有用。 问题是&#xff0c;如何结合文本和语义搜索结果&#xff1f; 首先&#xff0c;让我…

走向云原生 破局数字化

近年来&#xff0c;随着云计算概念和技术的普及&#xff0c;云原生一词也越来越热门&#xff0c;云原生成为云计算领域的新变量。行业内&#xff0c;华为、阿里巴巴、字节跳动等各个大厂都在“抢滩”云原生市场。行业外&#xff0c;云原生也逐渐出圈&#xff0c;出现在大众视野…

1.5 Unity中的数据存储 PlayerPrefs、XML、JSON

Unity中的三种数据存储&#xff1a;数据存储也称为数据持久化 一、PlayerPrefs PlayerPrefs是Unity引擎自身提供的一个用于本地持久化保存与读取的类&#xff0c;以键值对的形式将数据保存在文件中&#xff0c;然后程序可以根据关键字提取数值。 PlayerPrefs类支持3种数据类…

如何安装 Python

1.打开浏览器 输入网址 :www.python.org ​ 2.根据电脑系统配置进行下载 ​ 3.确定电脑系统属性&#xff0c;此处我们以win10的64位操作系统为例 ​ 4.安装python 3.6.3 双击下载的安装包 python-3.6.3.exe 注意要勾选&#xff1a;Add Python 3.6 to PATH 点击 Customize…

C#,入门教程(04)——Visual Studio 2022 数据编程实例:随机数与组合

上一篇&#xff1a; C#&#xff0c;入门教程(03)——Visual Studio 2022编写彩色Hello World与动画效果https://blog.csdn.net/beijinghorn/article/details/123478581 C#&#xff0c;入门教程(01)—— Visual Studio 2022 免费安装的详细图文与动画教程https://blog.csdn.net…

uniapp点击跳转传对象

目录 传对象传对象传送组件接受组件 最后 传对象 传对象 传送组件 点击传给组件 <view class"dki-tit-edit" click"gotificatedit(item)">编辑 </view>gotificatedit(item){console.log(item,item);let options JSON.stringify(item);uni.…

印象笔记02: 笔记本管理系统和空间使用

印象笔记02&#xff1a; 笔记本管理系统和空间使用 印象笔记新建笔记是一件非常容易的事情。笔记多了&#xff0c;就是归纳到笔记本里。 印象笔记一共有三层的笔记结构&#xff1a;最高层级是笔记本组&#xff0c;其次是笔记本&#xff0c;最后是一个个的笔记。合理的分类能够…

odoo17 | 用户界面的基本交互

前言 现在我们已经创建了我们的新模型及其 相应的访问权限&#xff0c;是时候了 与用户界面交互。 在本章结束时&#xff0c;我们将创建几个菜单以访问默认列表 和窗体视图。 数据文件 &#xff08;XML&#xff09; Odoo在很大程度上是数据驱动的&#xff0c;因此模块定义的…

C++中string的库函数

山再高&#xff0c;往上攀&#xff0c;总能登顶&#xff01; 路再长&#xff0c;走下去&#xff0c;定能到达&#xff01; &#x1f3a5;烟雨长虹&#xff0c;孤鹜齐飞的个人主页 &#x1f525;个人专栏c 期待小伙伴们的支持与关注&#xff01;&#xff01;&#xff01; 目录 前…

Python 面向对象之多态和鸭子类型

Python 面向对象之多态和鸭子类型 【一】多态 【1】概念 多态是面向对象的三大特征之一多态&#xff1a;允许不同的对象对同一操作做出不同的反应多态可以提高代码的灵活性&#xff0c;可扩展性&#xff0c;简化代码逻辑 【2】代码解释 在植物大战僵尸中&#xff0c;有寒冰…

扩展 apiserver 连接认证 ip, apiserver证书更新

本文来自我的博客地址 文章目录 问题场景:问题分析:问题解决:查看 apiserver 证书支持的 ip 或 host使用 openssl 生成证书:再次查看 apiserver 证书支持的 ip 或 host 再次尝试将 master 加点加入参考 问题场景: k8s 1.28.1 集群后期新增 vip apiserver 证书不支持 vip 引入…