Unix环境高级编程_进程环境_启动代码,环境变量表,进程内存结构,库

news2024/11/15 23:32:33

这是《UNIX环境高级编程》第7章内容,这篇文章记录进程所需要的环境。

4 进程环境

程序加载到内存,运行起来后就成为了进程。就像人活着需要生活环境(衣食住行的环境)一样,进程也需要运行环境,进程所需要的环境如下:启动代码、环境变量、进程的内存空间布局、库等,下面分别说这四点。

4.1 进程环境1:启动代码

启动代码就是启动程序的代码。所有高级语言的程序,都有自己的启动代码。C程序运行时,最开始运行的是启动代码,启动代码再去调用main函数,然后整个C程序都已运行。启动代码由编译器提供,其都是用汇编写的,为什么都是汇编写的呢?因为还没有程序内存空间之前,高级语言无法运行,所以启动代码都是汇编写的。

4.1.1 启动代码做的两件事

  • 对c程序的内存空间进行布局,得到c程序运行所需要的内存空间结构。
    高级语言程序在运行时,函数调用需要“栈”,启动代码就需要在c内存空间上建立“栈”,说白了就是从c内存空间中划出一段空间,然后以“栈”的形式来进行管理。
  • 留下相应库接口
    如果程序使用的是动态库的话,编译时,动态库代码并不会被直接编译到程序中,只会留下相应的接口,程序运行起来后,才会去对接库代码,为了能够对接动态库,启动代码会留下动态库的对接接口。

4.1.2 进程的终止方式

进程的正常终止

进程主动调用终止函数/返回关键字结束,就是正常终止。有三种方式:

  • 方式1:main调用return关键字结束
    return关键字的作用是返回上一级函数,如果main函数的子函数调用return,返回的上一级是main函数。如果main函数调用return,main函数所返回的上一级是启动代码。
  • 方式2:程序任何位置调用exit函数结束
    程序任意位置调用exit函数,程序返回到启动代码。Exit函数原型如下:
					#include <stdlib.h>
					void exit(int status);

看到stdlib.h这个头文件,我们就知道exit函数是一个c库函数。main函数调用return将返回值返回给启动代码后,启动代码又会调用exit(返回值),将返回值返回。
一般函数错误时候,会调用exit函数。

  • 方式3:程序任何位置调用_exit函数结束
    _exit是一个系统函数(系统API),而exit是c库函数,exit就是调用_exit来实现的。所以,exit是_exit的封装,比_exit多了很多功能。
    _exit函数原型:
				#include <unistd.h>
				void _exit(int status);
  • 总结这三种方式:
    return,exit,_exit都可以终止进程,但是尽量使用return和exit, 这三种方式的执行过程如下:
    Return:
    return(0) —————> exit(0) ————> _exit(0) ———> Linux OS
    ** exit**
    exit(0) ————————> _exit(0) ————> Linux OS
    ** _exit**
    _exit(0) ————>Linux OS
进程正常终止时候,注册进程终止函数

在写程序时候,可以使用atexit函数注册进程终止处理函数。函数原型如下:

#include <stdlib.h>
int atexit(void (*function)(void));

显然,这是一个C库函数。其功能是:
注册(登记)进程终止处理函数,参数就是被登记“进程终止函数”的地址。当进程无论什么时候正常终止时,会自动的去调用登记的进程终止处理函数,实现进程终止时的一些扫尾处理。

  • 代码演示:
#include <stdio.h>
#include <stdlib.h>

void process_deal1(void)
{
	printf("void process_deal1(void)\n");
}

void process_deal2(void)
{
	printf("void process_deal2(void)\n");
}

int main()
{
	atexit(process_deal1);
	atexit(process_deal2);

	while(1);

	return 0;

}

在这里插入图片描述
1)从这个实例中可以看出,进程终止处理函数的注册顺序和调用顺序刚好相反。
为什么顺序刚好相反呢?调用atexit注册时,会将“进程终止处理函数”的函数地址压入进程栈中,当进程正常终止时,又会自动从栈中取出函数地址,并执行这个函数,实现进程的扫尾操作。栈的特点是先进后出,先压栈的后调用,所以调用顺序刚好和注册顺序相反。
2)在Linux下,调用atexit最多可以允许登记32个终止处理函数。
3)同一个函数如果被登记多次,自然也会被调用多次。
4)在两种情况下,登记的进程终止处理函数不会被调用;
(a)异常终止,不会调用
(b)直接调用_exit来正常终止时,不会调用注册的进程终止函数。
换句话说,只有使用return和exit来正常终止时,才会调用。

登记“进程终止处理函数”有什么意义?

有时,代码正常终止时候,需要做一些扫码工作,比如保存链表中的数据等操作。如果不使用进程终止处理函数,这个操作有点困难,因为进程有时候可能是因为某个函数调用失败,然后在函数出错处理时调用exit(-1)终止的,但是你又无法预估哪一个函数会出错,并在出错时调用相应的函数实现链表数据的保存,那怎么办呢?这个时候就可以注册进程终止处理函数来实现了,因为进程终止时,会自动的调用终止处理函数来实现进程的扫尾处理,比如将链表数据保存到文件中。

#include <stdio.h>
#include <stdlib.h>

void process_deal1(void)
{
	printf("void process_deal1(void)--save list\n");
}

void process_deal2(void)
{
	printf("void process_deal2(void)\n");
}

void fun1()
{
	exit(-1);
}
int main()
{
	atexit(process_deal1);
	atexit(process_deal2);

	fun1(); // 程序正常终止

	return 0;
}

在这里插入图片描述

进程的异常终止

有些情况下,进程不是因为return、exit和_exit函数而终止的,而是被强行发送了一个信号,这个信号将进程给无条件终止了,这就是异常终止。在命令行下按下ctrl + c, 就是在向正在运行的进程发送终止信号,这个信号将异常终止程序。

4.1.3 进程启动到正常终止的全过程

在这里插入图片描述

  • 上图中,为什么调用exit会刷新io缓冲区 ?
    标准IO的库缓存的缓冲有三种,无缓冲、行缓冲、全缓冲。标准输出(printf)的库缓存就是行缓冲的,在缓存中积压的数据,直到出现以下情况时,才会刷新输出,否则就一直积压着。
    **1)**遇到\n时就刷新输出,\n表示这是一行,就好比句号表示一句话一样。
    **2)**库缓存中数据满了,也会自动刷新输出,这就好比盆里的水满了溢出一样。不过一般来说,数据不可能多到能够把缓存装满的。
    **3)**调用标准fflush函数,主动刷新数据
    **4)**调用fclose关闭标准输出时,会自动调用fflush刷洗数据;
    exit会调用fclose关闭所有的标准io关闭时会自动调用fflush来刷新数据。

4.2 进程环境2:环境变量表

先说下什么是环境变量?环境变量就是字符串,环境变量 = 环境变量名 + 环境变量数据,比如在windows下设置的环境变量如下图所示,其作用是**:专门记录各种可执行程序所在的路径。**
在这里插入图片描述
环境变量存放在“环境变量表”里面。每个进程都有一张环境变量表,最原始的“环境变量表”都被保存在了“环境变量文件”中。通过修改环境变量文件,实现了“环境变量”数据的永久保存。我们通过图形界面设置、修改windows“环境变量”时,修改、设置的内容,都会被永久保存到“环境变量文件”中。
当我们在linux命令行下面,执行自己的./a.out程序时候,查找的谁的环境变量表呢?
查找的是“命令行窗口进程”的“环境变量表”。
为什么只有重新打开“命令行窗口”后, 新设置的“环境变量”才生效?
因为新设置的环境变量,只是被保存到了windows的环境变量文件中,但是之前所打开的“命令行窗口”进程的“环境变量表”还没有得到更新,只有当重新打开后,才能更新。

4.3 进程环境3:进程的内存布局

编译好的C程序,需要加载到内存中,然后才能运行。所以,启动代码需要在内存中开辟好进程需要的空间给程序时候,有虚拟内存的OS,进程的空间布局在虚拟内存上,CPU执行的虚拟内存的地址。进程的内存布局如下:
在这里插入图片描述

4.4 进程环境4:库

当我们写程序时候,也需要库,比如使用printf函数,就是标准库中的函数。又比如使用别人写的好用的库,所以库也是程序必须可少的,有库的支持,我们可以更方便的写程序。

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

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

相关文章

Vue组件生命周期与钩子函数

组件生命周期 ​ 组件&#xff08;组件是可复用的 Vue 实例&#xff09;从创建到销毁的过程就是组件的生命周期&#xff0c;是一个时间段。 组件生命周期钩子函数 &#xff08;vue3与vue2生命周期钩子函数略有不同&#xff0c;本文以vue2为主&#xff09; ​ VUE 提供的生命…

科研快报 | 三代测序技术-海水微生物态,助力海水微生态及微生物基因组研究

PacBio研究专题二代测序读长偏短&#xff0c;环境宏基因组样品研究受到了很大限制。作者通过三代测序对来自地中海的冬季混合海水样本进行宏基因组测序。利用PacBio Sequel II平台的超长读长明显可以提升宏基因组的组装质量&#xff0c;又能显著提升MAGs质量。研究人员通过比较…

使用和登录Linux云服务器

目录 云服务器的购买 SSH登录云服务器 云服务器的购买 我们以腾讯云为例, 其他的服务器厂商也是类似。 1. 进入腾讯云官方网站&#xff1a;学生云服务器_云校园特惠套餐 - 腾讯云 (tencent.com) 2. 登陆网站(可以使用微信登陆) 3.购买云服务器 购买最低级即可&#xff0c;对于…

python - 科研文献作图复现1

记录阅读文献过程中&#xff0c;通过python复现原文的一些脚本 想要复现的文章原图如下所示 原文链接&#xff1a; https://file.scirp.org/Html/4-2430166_82999.htm 首先&#xff0c;对于原图进行简要观察。 这是一张折线图&#xff0c;绘制了6条不同颜色的折线来表示不同…

舆情监控软件免费下载,TOOM网络舆情监控软件服务流程?

舆情监测可以帮助个人和企业了解自己的网络形象&#xff0c;提高自我评价和评价能力&#xff0c;提升自我定位和竞争力。接下来简单了解舆情监控软件免费下载&#xff0c;TOOM网络舆情监控软件服务流程? 一、舆情监控软件免费下载 请登录TOOM舆情官网获取链接 1.企业客户&a…

SpringMVC(十三):SpringMVC拦截器介绍使用

文章目录 SpringMVC拦截器介绍使用 前言 一、拦截器使用 二、拦截器内容详解 1、preHandle方法 2、postHandle方法 3、afterCompletion方法 三、多个拦截器执行顺序 SpringMVC拦截器介绍使用 前言 在之前的系列文章里&#xff0c;我们学习了过滤器的知识。过滤器的作…

ejs模板在Express框架中的集成

在上一篇内容中已经使用了pug模板&#xff0c;那么本篇就来了解一下ejs模板在Express框架中的集成使用&#xff0c;ejs模板也是常用的模板引擎&#xff0c;支持在标签内直接编写javascript代码&#xff0c;通过javascript代码就能够生成HTML页面的&#xff0c;通过本期对ejs模板…

C++字符串全排列(递归法)和(迭代法)以及next_permutation底层原理详解

目录前言next_permutation的使用实现全排列的两种算法1. 递归法(全排列方便理解记忆的方法&#xff0c;作为备用方法)实现代码(无重复元素情况)有重复元素情况2. 迭代法(next_permutation底层原理)实现代码(有无重复不影响)前言 next_permutation/prev_permutation是C STL中的…

全国青少年软件编程(Python)等级考试一级考试真题2022年12月——持续更新.....

1.关于Python语言的注释,以下选项中描述错误的是?( ) A.Python语言有两种注释方式:单行注释和多行注释 B.Python语言的单行注释以#开头 C.Python多行注释使用###来做为标记 D.注释用于解释代码原理或者用途 正确答案:C 2.下列代码执行后最有可能绘制出的图形是?(…

网络原理(TCP/IP五层协议)(三)

目录4.滑动窗口(效率机制)5.流量控制(安全机制)6.拥塞控制(安全机制)7.延迟应答(效率机制)8.捎带应答(效率机制)9.面向字节流10.TCP的异常处理4.滑动窗口(效率机制) 滑动窗口存在的意义就是在保证可靠性的前提下&#xff0c;尽量提高传输效率。 在这里可以看到&#xff0c;由于…

JSP 学生成绩管理系统myeclipse定制开发sqlserver数据库网页模式java编程jdbc

一、源码特点 JSP 学生成绩管理系统是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为SQLServer2008&#x…

layui 富文本layedit编辑、存储和回显

一、创建一个富文本编辑框 先定义一个textarea标签&#xff0c;给定一个id值&#xff0c;向页面引入layedit&#xff0c;然后调用layedit.build(id, options)构建富文本框 //官方给出的模板 <textarea id"demo" style"display: none;"></textar…

Linux的目录相关操作

目录 前言 处理目录的常见命令 cd&#xff08;change directory&#xff0c;切换目录&#xff09; pwd&#xff08;print working directory&#xff0c;显示目前所在的目录&#xff09; mkdir&#xff08;make directory&#xff0c;建立新目录&#xff09; rmdir&#x…

代码随想录算法训练营第十三天 | 第六章二叉树-理论基础,递归遍历,迭代遍历,统一迭代

一、参考资料二叉树理论基础文章讲解&#xff1a;https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 递归遍历题目链接/文章讲解/视频讲解&#xff1a;https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%8…

Mobilenet v1-v3

MobileNet V1 理解 MobileNetV1的关键是理解深度可分离卷积 深度可分离卷积 Depthwise Separable Conv 深度可分离卷积单通道卷积&#xff08;提取特征&#xff09;逐点卷积&#xff08;增加维度&#xff09; 普通卷积 输入一个 12123 的一个输入特征图&#xff0c;经过256…

微服务/分布式初始

1.单体服务架构的特点 当服务单一、规模小、逻辑简单时&#xff0c;用一个单体服务就挺 单体服务的缺点 复杂程度高。维护成本越来越高&#xff0c;各个模块之间边界模糊&#xff0c;一个模块的改动可能导致整个服务出现问题&#xff0c;一点内存泄漏、一处指针错误就会让整…

汉诺塔+汉诺四塔(C/C++)

目录 汉诺塔 1 简介 2 代码思路 2.1 对于次数的理解 2.2 对于移动的理解 3 代码 4 加深理解 汉诺四塔 1 思路 2 代码 汉诺塔 1 简介 汉诺塔(Tower of Hanoi)&#xff0c;又称河内塔&#xff0c;是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三…

关于e^x的部分公式和约算方法

常用的几个不等式: ex≥x1e^{x}\geq x1ex≥x1ln⁡x≤x−1\ln x\leq x-1lnx≤x−1ex≥exe^{x} \geq exex≥exex≥1xx22e^x\geq1x\frac{x^2}{2}ex≥1x2x2​ 当x>0时&#xff0c;ex≥ex(x−1)2x2−(e−2)x1e^x\geq ex(x-1)^{2}x^2-(e-2)x1ex≥ex(x−1)2x2−(e−2)x1 上述算式在…

数据库系统概论——函数依赖、码和范式(1NF、2NF、3NF、BCNF)详解

文章目录概念回顾1、函数依赖的定义1.1 平凡函数依赖和非平凡函数依赖1.2 完全函数依赖和部分函数依赖1.3 传递函数依赖2、码2.1 主码和候选码2.1主属性与非主属性2.2 全码2.3 外部码3、范式3.1 第一范式&#xff08;1NF&#xff09;3.2 第二范式&#xff08;2NF&#xff09;3.…

现在的互联网技术,已蜕变成区块链技术,人工智能技术

在互联网的进化过程中&#xff0c;我们看到了互联网技术的不断孪生与蝶变。现在的互联网技术&#xff0c;早已不再是传统意义上的互联网技术&#xff0c;而是蜕变成为了大数据技术&#xff0c;云计算技术&#xff0c;蜕变成为了区块链技术&#xff0c;人工智能技术。这些新的技…