Linux 第十九章

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++,linux

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

mm_struct

写时拷贝

fork

fork常规用法​​​​​​​

fork调用失败的原因

创建一个多进程

进程终止

main函数的返回值

strerror

​​​​​​​有时候用echo $?显示退出码并不和库里标准的对应

C语言的错误码


mm_struct

写时拷贝

父进程创建子进程的时候,首先将自己的页表读写权限改为只读,然后再创建子进程

(注意:代码段一直是只读的),但是这个过程用户是不知道的!用户就有可能对某一批数据进行写入!

此时,页表就会因为权限问题出错

1)真的出错了,例如用户想要修改代码的数据

2)例如用户想要修改数据段的数据,操作系统就会重新申请内存

注意:

1.在地址空间里面绝对不会出现划分的区域重叠的

2.Os操作系统肯定知道我们在读还是在写

为什么子进程发生写时拷贝的时候,需要拷贝父进程数据段的代码再进行写入,而不是直接申请空间直接写入呢?

子进程不一定要对父进程数据段全部进行修改,可能修改一部分

fork

fork常规用法​​​​​​​

1.一个父进程希望复制自己,使父子进程同时执行不同的代码段,例如,父进程等待客户端请求,生成子进程来处理请求。

2.一个进程执行一个不同的程序。例如子进程从fork返回后,调用exec函数

fork调用失败的原因

fork失败的返回值小于0

1.系统进程太多

2.实际用户的进程数超过了限制

创建一个多进程

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#define N 10
typedef void (*callback_t)();//函数指针

void Worker()//子进程执行的方法
{
        int cnt=10;
        while(cnt)
        {
                printf("I am child process,pid:%d ,ppid: %d ,cnt:%d\n",getpid(),getppid(),cnt);
                sleep(1);
                cnt--;
        }


}
void createSubProcess(int n,callback_t cb)//创建n个子进程+
{


        int i=0;
        for(i=0;i<n;i++)
        {
                sleep(1);
                pid_t id=fork();
                if(id==0)
                {
                        printf("create child process success:%d\n",i);
                        //child
                        cb();
                        exit(0);
                }
        }


}


int main()
{
        createSubProcess(N,Worker);
        //只有父进程走到这里
        sleep(100);
        return 0;
}

当n个子进程运行完之后,父进程并没有结束(因为sleep(100)),所以子进程就会形成僵尸进程
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
17831 26353 26353 17831 pts/0    26353 S+    1000   0:00 ./myprocess
26353 26380 26353 17831 pts/0    26353 Z+    1000   0:00 [myprocess] <defunct>
26353 26458 26353 17831 pts/0    26353 Z+    1000   0:00 [myprocess] <defunct>
26353 26540 26353 17831 pts/0    26353 Z+    1000   0:00 [myprocess] <defunct>
26353 26555 26353 17831 pts/0    26353 Z+    1000   0:00 [myprocess] <defunct>
26353 26629 26353 17831 pts/0    26353 Z+    1000   0:00 [myprocess] <defunct>
26353 26711 26353 17831 pts/0    26353 Z+    1000   0:00 [myprocess] <defunct>
26353 26758 26353 17831 pts/0    26353 Z+    1000   0:00 [myprocess] <defunct>
26353 26808 26353 17831 pts/0    26353 Z+    1000   0:00 [myprocess] <defunct>
26353 26882 26353 17831 pts/0    26353 Z+    1000   0:00 [myprocess] <defunct>
26353 26929 26353 17831 pts/0    26353 Z+    1000   0:00 [myprocess] <defunct>

进程终止

main函数的返回值

[BCH@hcss-ecs-6176 ~]$ cat test.c
#include<stdio.h>
int main()
{
        return 10;
}

[BCH@hcss-ecs-6176 ~]$ ./mytest
[BCH@hcss-ecs-6176 ~]$ echo $?//获取main函数的返回值
10

?:保存的就是最近一个子进程执行完毕时的退出码
就类似于 echo $环境变量 将环境变量的内容输出到屏幕上
echo $?将最近一个子进程执行完毕时的退出码输出到屏幕上

在多进程环境中,我们(父进程)创建子进程的目的是什么?
帮我们办事


子进程把事情办得怎么样呢??

main函数的返回值,就叫做进程的退出码,0->成功,非0表示失败
非0的时候,这个进程因为什么原因失败!
1,2,3,4,5,6……我们可以用不同的数字表示不同的原因!!

纯数字能表示出错原因,但是不便于人阅读,exit code->exit code string (将数字转化为字符串的形式便于人去阅读)

strerror

在C语言中,strerror是一个库函数,用于将错误码或退出码转换为对应的错误消息字符串。

通过strerror查看linux中c的退出码(错误码)
[BCH@hcss-ecs-6176 ~]$ cat test.c
#include<stdio.h>
#include<string.h>
int main()
{
        int i=0;
        for(i=0;i<200;i++)//之所以是200,因为我不知道linux中退出码的范围(实际上退出码的范围0-133)
        {
                printf("%d:%s\n",i,strerror(i));
        }
        return 10;
}

[BCH@hcss-ecs-6176 ~]$ ./mytest
0:Success
1:Operation not permitted
2:No such file or directory
3:No such process
4:Interrupted system call
5:Input/output error
6:No such device or address
7:Argument list too long
8:Exec format error
9:Bad file descriptor
10:No child processes
11:Resource temporarily unavailable
12:Cannot allocate memory
13:Permission denied
14:Bad address
15:Block device required
16:Device or resource busy
17:File exists
18:Invalid cross-device link
19:No such device
20:Not a directory
21:Is a directory
22:Invalid argument
23:Too many open files in system
24:Too many open files
25:Inappropriate ioctl for device
26:Text file busy
27:File too large
28:No space left on device
29:Illegal seek
30:Read-only file system
31:Too many links
32:Broken pipe
33:Numerical argument out of domain
34:Numerical result out of range
35:Resource deadlock avoided
36:File name too long
37:No locks available
38:Function not implemented
39:Directory not empty
40:Too many levels of symbolic links
41:Unknown error 41
42:No message of desired type
43:Identifier removed
44:Channel number out of range
45:Level 2 not synchronized
46:Level 3 halted
47:Level 3 reset
48:Link number out of range
49:Protocol driver not attached
50:No CSI structure available
51:Level 2 halted
52:Invalid exchange
53:Invalid request descriptor
54:Exchange full
55:No anode
56:Invalid request code
57:Invalid slot
58:Unknown error 58
59:Bad font file format
60:Device not a stream
61:No data available
62:Timer expired
63:Out of streams resources
64:Machine is not on the network
65:Package not installed
66:Object is remote
67:Link has been severed
68:Advertise error
69:Srmount error
70:Communication error on send
71:Protocol error
72:Multihop attempted
73:RFS specific error
74:Bad message
75:Value too large for defined data type
76:Name not unique on network
77:File descriptor in bad state
78:Remote address changed
79:Can not access a needed shared library
80:Accessing a corrupted shared library
81:.lib section in a.out corrupted
82:Attempting to link in too many shared libraries
83:Cannot exec a shared library directly
84:Invalid or incomplete multibyte or wide character
85:Interrupted system call should be restarted
86:Streams pipe error
87:Too many users
88:Socket operation on non-socket
89:Destination address required
90:Message too long
91:Protocol wrong type for socket
92:Protocol not available
93:Protocol not supported
94:Socket type not supported
95:Operation not supported
96:Protocol family not supported
97:Address family not supported by protocol
98:Address already in use
99:Cannot assign requested address
100:Network is down
101:Network is unreachable
102:Network dropped connection on reset
103:Software caused connection abort
104:Connection reset by peer
105:No buffer space available
106:Transport endpoint is already connected
107:Transport endpoint is not connected
108:Cannot send after transport endpoint shutdown
109:Too many references: cannot splice
110:Connection timed out
111:Connection refused
112:Host is down
113:No route to host
114:Operation already in progress
115:Operation now in progress
116:Stale file handle
117:Structure needs cleaning
118:Not a XENIX named type file
119:No XENIX semaphores available
120:Is a named type file
121:Remote I/O error
122:Disk quota exceeded
123:No medium found
124:Wrong medium type
125:Operation canceled
126:Required key not available
127:Key has expired
128:Key has been revoked
129:Key was rejected by service
130:Owner died
131:State not recoverable
132:Operation not possible due to RF-kill
133:Memory page has hardware error
134:Unknown error 134//这里已经没有了

连续echo $?

[BCH@hcss-ecs-6176 ~]$ echo $?
10
[BCH@hcss-ecs-6176 ~]$ echo $?
0
[BCH@hcss-ecs-6176 ~]$ echo $?
0

为什么第一个echo $?输出的就是10,第二个echo $?输出就是0呢?

因为第一个echo $?中的?保留的是./mytest进程的退出码,而./mytest进程的退出码是10,

第二个echo $?中的?保留的是第一个echo $?这个进程的退出码,因为第一个echo $?进程退出码是0

​​​​​​​有时候用echo $?显示退出码并不和库里标准的对应

[BCH@hcss-ecs-6176 ~]$cd /home/wcq
bash: cd: /home/wcq: Permission denied
[BCH@hcss-ecs-6176 ~]$echo $?
1
库里13:Permission denied,Permission denied表示的退出码是13
但是echo $?显示的值是1
所以这里用退出码不是使用的C语言标准库的,而是使用的自定义的

main函数的退出码是可以被父进程获取的,用来判断子进程的运行结果

C语言的错误码

c语言中的全局变量errno
在C语言中,errno是一个全局变量,用于表示最近一次发生的错误码。它定义在 <errno.h> 头文件中。


错误码VS退出码
错误码通常是衡量一个库函数或者是一个系统调用一个函数的调用的情况
退出码通常是一个进程退出的时候,他退出结果

当失败的时候,用来衡量函数,进程出错时的出错详细信息原因

linux内核是c语言写的,linux中很多的系统调用就设置了errno

一般代码出异常,代码是没有运行完的

异常问题——引入一下
[BCH@hcss-ecs-6176 ~]$ cat test.c
#include<stdio.h>
#include<string.h>
int main()
{
        int a=10;
        a/=0; 
}
[BCH@hcss-ecs-6176 ~]$ ./mytest
浮点数例外//异常

[BCH@hcss-ecs-6176 ~]$ cat test.c
#include<stdio.h>
#include<string.h>
int main()
{
        
        int *p=NULL;
        *p=100;
        return 10;
}
[BCH@hcss-ecs-6176 ~]$ ./mytest
段错误//异常
进程异常会被os杀掉这个进程(kill)
进程异常的时候,会转化成信号,会被os检测到的

结论:进程出异常,本质是进程收到了对应的信号,自己终止了!!

  🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据可视化-02】Seaborn图形实战宝典

Seaborn介绍 Seaborn是一个基于Python的数据可视化库&#xff0c;它建立在matplotlib的基础之上&#xff0c;为统计数据的可视化提供了高级接口。Seaborn通过简洁美观的默认样式和绘图类型&#xff0c;使数据可视化变得更加简单和直观。它特别适用于那些想要创建具有吸引力且信…

后端接口返回二进制数据流,前端如何将其转换成对应的excel、csv和json文件格式并下载

本文主要是介绍在工作中遇到的后端接口返回一个二进制数据流&#xff0c;前端在界面上创建下载按钮并下载成对应格式的文件导出。 downloadData({start: startTime,end: endTime,exportType: 0, // 0-excel, 1-csv, 2-json }).then((res) > {download(res, startTime, endTi…

Flutter笔记:Widgets Easier组件库 - 使用标签(Tag)

Flutter笔记 Widgets Easier组件库 - 使用标签&#xff08;Tag&#xff09; - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this …

【网络原理】IP协议详解

一.与IP协议相关的基本概念 IP协议&#xff0c;即网际互连协议&#xff08;Internet Protocol&#xff09;&#xff0c;是TCP/IP体系中的核心网络层协议。 网络层IP协议解决的问题 数据传输的过程中,不是直接进行的传输,而是经过层层的封装和分用的过程才能到达对端. IP协议主…

计算机是如何执行指令的

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

19 内核开发-内核源码编译

19 内核开发-内核源码编译 (1)开始准备 安装好virtual box ubuntu 系统后&#xff0c;即可下载内核代码&#xff0c;进行编译 历史内核源码地址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/kernel/v5.x/ 下载 linux-5.10.102.tar.gz 的包,可以使用wget 命令 创建编译目…

CasaOS玩客云安装memos开源云笔记并实现随时随地远程记笔记

文章目录 前言1. 使用Docker部署memos2. 注册账号与简单操作演示3. 安装cpolar内网穿透4. 创建公网地址5. 创建固定公网地址 前言 本文主要介绍如何在CasaOS玩客云&#xff0c;使用Docker本地部署21.6K stars的热门开源云笔记服务memos&#xff0c;并结合cpolar内网穿透工具打…

基于Springboot的校园志愿者管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校园志愿者管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结…

土壤重金属含量分布、Cd镉含量、Cr、Pb、Cu、Zn、As和Hg、土壤采样点、土壤类型分布

土壤是人类赖以生存和发展的重要资源之一,也是陆地生态系统重要的组成部分。近年来, 随着我国城市化进程加快&#xff0c;矿产资源开发、金属加工冶炼、化工生产、污水灌溉以及不合理的化肥农药施用等因素导致重金属在农田土壤中不断富集。重金属作为土壤环境中一种具有潜在危害…

软件测试与管理-白盒测试-逻辑覆盖法例题

目录 知识点&#xff1a; 例题 &#xff1a; 知识点&#xff1a; 语句覆盖&#xff1a;设计足够多的测试用例&#xff0c;使得被测试程序中的“ 每条可执行语句至少被执行一次” 优点&#xff1a;可通过源码观察直观地得到测试用例&#xff0c;无须细分每个判定表达式。缺点&am…

2024-5-3学习笔记 虚拟继承原理

目录 原理 总结 前面提到过&#xff0c;解决菱形继承产生的数据二义性问题和数据冗余&#xff0c;就需要用到虚拟继承&#xff0c;关于它是如何解决的&#xff0c;我们来一起研究。 class Person { public :string _name ; // 姓名 }; class Student : virtual public Perso…

Chrome浏览器命令行妙用:使你的网上冲浪更加无障碍

引言 在当今数字化时代&#xff0c;网络浏览器已成为我们日常生活中不可或缺的工具之一。对于许多人来说&#xff0c;Google Chrome浏览器是首选&#xff0c;不仅因为它的普及度&#xff0c;更因为它提供的丰富功能和高度的可定制性。在Chrome的众多特性中&#xff0c;命令行功…

Pytorch实现图片异常检测

图片异常检测 异常检测指的是在正常的图片中找到异常的数据&#xff0c;由于无法通过规则进行识别判断&#xff0c;这样的应用场景通常都是需要人工进行识别&#xff0c;比如残次品的识别&#xff0c;图片异常识别模型的目标是可以代替或者辅助人工进行识别异常图片。 AnoGAN…

Linux-信号概念

1. 什么是信号 信号本质是一种通知机制&#xff0c;用户or操作系统通过发送信号通知进程&#xff0c;进程进行后续处理 在日常生活中就有很多例子&#xff0c;比如打游戏方面王者荣耀的“进攻”&#xff0c;“撤退”&#xff0c;“请求集合”&#xff0c;“干得漂亮&#xff01…

【一步一步了解Java系列】:探索Java基本类型转换的秘密

看到这句话的时候证明&#xff1a;此刻你我都在努力~ 加油陌生人~ 个人主页&#xff1a; Gu Gu Study ​​ 专栏&#xff1a;一步一步了解Java 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努力留下足迹。 如果喜欢能否点个赞支持一下&#…

第四百九十二回

文章目录 1. 概念介绍2. 使用方法2.1 SegmentedButton2.2 ButtonSegment 3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"SearchBar组件"相关的内容&#xff0c;本章回中将介绍SegmentedButton组件.闲话休提&#xff0c;让我们一起Talk …

Java面试题:多线程3

CAS Compare and Swap(比较再交换) 体现了一种乐观锁的思想,在无锁情况下保证线程操作共享数据的原子性. 线程A和线程B对主内存中的变量c同时进行修改 在线程A中存在预期值a,修改后的更新值a1 在线程B中存在预期值b,修改后的更新值b1 当且仅当预期值和主内存中的变量值相等…

Llama3-Tutorial之XTuner微调Llama3个人小助手

Llama3-Tutorial之XTuner微调Llama3个人小助手 使用XTuner微调llama3模型。 参考&#xff1a; https://github.com/SmartFlowAI/Llama3-Tutorial 1. web demo部署 参考上一节内容已经完成web demo部署&#xff0c;进行对话测试, 当前回答基于llama3官方发布的模型进行推理生成&…

MySQL基础_5.多表查询

文章目录 一、多表连接1.1、笛卡尔积&#xff08;或交叉连接&#xff09; 二、多表查询&#xff08;SQL99语法&#xff09;2.1、内连接(INNER JOIN)2.2、内连接(INNER JOIN) 一、多表连接 多表查询&#xff0c;也称为关联查询&#xff0c;指两个或更多个表一起完成查询操作。 …

利用matplotlib和networkx绘制有向图[显示边的权重]

使用Python中的matplotlib和networkx库来绘制一个有向图&#xff0c;并显示边的权重标签。 1. 定义了节点和边&#xff1a;节点是一个包含5个节点的列表&#xff0c;边是一个包含各个边以及它们的权重的列表。 2. 创建了一个有向图对象 G。 3. 向图中添加节点和边。 4. 设置了…
最新文章