进程环境--进程管理

发布时间 - 2017-07-23 00:00:00    点击率:

程序执行时,main函数是如何被调用的,命令行参数是如何传递给程序的,典型的存储空间布局是什么样式,如何分配其他存储空间,进程如何使用环境变量,进程的终止等等这些都是进程控制的基础知识。


进程的启动和终止

内核执行c程序时,利用exec函数调用一个特殊的启动例程,该启动例程丛内核中获取命令行参数和环境变量值。

进程终止的情况

5种正常终止的情况:

(1)从main函数返回;
(2)调用exit;
(3)调用_exit和_Exit函数;
(4)最后一个线程调用pthread_exit;
(5)最后一个线程从其启动例程返回;

3种异常终止情况

(1)调用abort;
(2)接到一个信号;
(3)最后一个线程对取消请求做出响应;

进程启动和终止图

atexit函数

一个进程最多可以登记32和函数(例如:signal函数),这些函数由exit函数自动调用。在程序终止时调用这些函数,形成终止处理程序,来进行结束进程前的收尾工作。而exit函数通过atexit函数的登记记录来判断调用哪些函数。

exit函数

此函数由ISO C 定义,其操作包括处理终止处理程序,然后关闭所有标准I/O流。需要注意的是,它不会处理文件描述符、多进程(父子进程)以及作业控制。

_e(E)xit函数
ISO C 定义这个函数的目的是为进程提供一种无需运行终止处理程序或信号处理函数的方法而终止程序。但ISO C 对标准I/O流是否进行冲洗,这取决于操作系统的实现。在unix中,是不进行冲洗的。

exit和_e(E)ixt函数的状态码

无论进程怎样结束,它都会在内核上执行同一段代码(由进程启动和退出图可知)。这段代码来关闭所有的文件描述符,释放所有的存储空间。

程序退出后,利用退出码告知该进程的父进程。父进程通过wait或waitpid函数来完成该子进程的善后工作(获取子进程相关信息 释放子进程占用资源)。若父进程没有处理子进程的退出状态,则子进程变成僵死进程。相反的,若父进程在子进程前终止,则子进程变成孤儿进程。孤儿进程会由1号进程(init进程)接收,大致过程如下:

(1)进程终止时,内核逐个检查所有活动的进程;
(2)分析查找该终止进程的子进程;
(3)将该进程的子进程的父进程ID改为1;

wait和waitpid函数

程序正常或异常终止时,内核都会向父进程发送SIGNAL信号。子进程终止是异步事件,所以该信号也是异步信号。而该信号一般会被父进程默认忽略。或者提供一个信号处理函数来善后。wait和waitpid函数就是其中的信号处理函数的一部分。

wait和waitpid函数区别如下:

(1)wait会阻塞调用者进程等待直至第一个终止的子进程到来;
(2)waitpid可以通过参数设置,来实现调用者进程不阻塞,或选择要阻
塞等待的子进程;

这里的调用者指的是父进程

环境表和环境变量

环境表结构图

  • 每个程序都接收到一张环境表

  • 环境表也是一个字符指针数组

  • enrivon叫做环境指针

  • 指针数组叫做环境表

  • 各个指针指向的字符串叫做环境字符串

环境变量

  • unix内核并不检查环境字符串,它们的解释完全取决于各个应用进程

  • 通常在一个shell启动文件中设置环境变量来控制shell的动作

  • 修改或者增加环境变量时,只能影响当前进程以及其后(之前的不行)生成和调用的任何子进程的环境,但不能影响其父进程的环境

和环境变量相关的函数如下:

#include
char *getenv(const char *name);
      返回值:指向与name关联的value的指针;若未找到,返回NULL

int putenv(char *str);
                       返回值:若成功,返回0;若出错,返回非0
                       
int setenv(const char *name, const char *value,
            int rewrite);
int unsetenv(const char *name);
                两个函数返回值:若成功,返回0;若出错,返回-1

这些函数如何修改环境表的

环境表和环境字符串通常存放在内存空间的高地址处(顶部)。所以在修改它的值时,内存是不能继续向高地址延伸;但又因为,它之下是各个栈帧,所以也不能向下延伸。如何修改它的值的过程如下:

(1)修改环境表

1)新value <= 旧value,直接覆盖旧value的存储空间
2)新value >= 旧value,调用malloc函数,在堆区开辟新的存储空间,
将新value复制到这里,再将这片存储区首地址写到环境表相应的位置处。

(2)新增环境表

1)新增一个环境变量,调用malloc函数开辟新的存储空间,将原来的环
境表复制到该存储区,其次再添加一个环境变量,然后在尾部赋值为NULL,
最后将environ指向该区域;
2)在 1)过程的基础上,调用realloc函数,多次添加环境变量;

注意:以这种方式修改的环境变量只在当下程序运行时有效,当程序结束时,相应的存储区被系统回收,这些修改就会失效。

内存存储结构补充说明

内存管理结构图

  • 未初始化数据段(block started by symbol):在程序开始执
    行之前,内核将此段中的数据初始化为0或空指针;

  • 栈:每次函数调用时,其返回地址以及调用者的环境信息(如某些机器寄存器的值)都存放在栈中;

  • 共享库:只需在所有进程都可引用的存储区中保存这种库例程的一个副本;

存储空间分配函数

#include
void *malloc(size_t size);
void *calloc(size_t nojy, size_t size);
void *realloc(void *ptr, size_t newsize);
         3个函数返回值:若成功,返回非空指针;若出错,返回NULL
  • malloc函数:初始值不确定;底层通过调用sbrk函数实现;

  • calloc函数:初始值为0;

  • realloc函数:增加或减少以前分配区的长度;当增加长度时,可能将以前分配区的内容移到另一个足够大的区域,以便在分配区末尾增加存储区,而新增存储区初始值不确定(例如:可变数组的使用);

注意:这些动态分配的函数一般在分配存储空间时,会比要求的大。因为在开辟空间的前后部分存储记录管理信息。因此,在使用时,千万不要越界访问,以免造成不可预知的后果。

函数间跳转策略

在c语言中,goto语句是不能跨函数跳转的。尤其是在函数深层调用时的跳转需求,在出错处理的情况下非常有用。

#include
int setjmp(jmp_buf env);
          返回值:若直接调用,返回0;若从longjmp返回,返回非0
void longjmp(jmp_buf env, int val);

变量值回滚问题:自动变量和寄存器变量会存在回滚现象。利用volatile属性来避免此类情况的发生。(在给变量赋值时,赋的值回首先存储在内存(存储器变量)中,然后在由cpu取走,存储在cpu的寄存器上(寄存器变量)。在做系统优化时,那些频繁使用的变量,会直接存储到寄存器中而不经过内存。)

寄存器变量会存在回滚现象的探究

在调用setjmp函数时,内核会把当前的栈顶指针保存在env变量中,所以在调用longjmp函数返回该位置时,全局变量、静态变量、易失变量和自动变量如果在调用setjmp和longjmp函数之间它们的值被修改过,是不会回滚到setjmp函数调用之前的值(当然,编译器将auto变量优化为寄存器变量除外)。因为,这些存储器变量的值是存储在内存相应的段中,回到原先栈顶状态时,同样访问的还是原先的内存空间。

然而,对于寄存器变量来说,首先要明确一点:寄存器变量是用动态存储的方式。意思是寄存器变量的值可能存在不同的寄存器中。如果在调setjmp和longjmp函数之间它们的值被修改过,这个值可能不会存到setjmp之前的对其赋值的寄存器中,而在调用longjmp函数后,又回到了调用setjmp函数时的状态。这个时候再读取寄存器变量的值时,读到的是原先那个寄存器中存储的值而不是修改过的那个寄存器中存储的值,所以出现的回滚现象。


# 返回值  # 器中  # 的是  # 跳转  # 例程  # 调用者  # 结构图  # 信号处理  # 不确定  # 命令行 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel Blade模板引擎语法_Laravel Blade布局继承用法  Laravel如何使用模型观察者?(Observer代码示例)  如何基于云服务器快速搭建网站及云盘系统?  如何在IIS中新建站点并配置端口与IP地址?  html5的keygen标签为什么废弃_替代方案说明【解答】  小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?  Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程  百度输入法ai面板怎么关 百度输入法ai面板隐藏技巧  Bootstrap整体框架之JavaScript插件架构  企业网站制作这些问题要关注  如何在景安云服务器上绑定域名并配置虚拟主机?  Laravel怎么做数据加密_Laravel内置Crypt门面的加密与解密功能  Python自动化办公教程_ExcelWordPDF批量处理案例  香港服务器网站搭建教程-电商部署、配置优化与安全稳定指南  laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法  高防网站服务器:DDoS防御与BGP线路的AI智能防护方案  Laravel怎么配置S3云存储驱动_Laravel集成阿里云OSS或AWS S3存储桶【教程】  高防服务器租用指南:配置选择与快速部署攻略  Laravel如何实现用户密码重置功能?(完整流程代码)  Laravel如何实现多对多模型关联?(Eloquent教程)  微信小程序 配置文件详细介绍  黑客入侵网站服务器的常见手法有哪些?  js实现点击每个li节点,都弹出其文本值及修改  JS经典正则表达式笔试题汇总  Android滚轮选择时间控件使用详解  Laravel如何使用查询构建器?(Query Builder高级用法)  如何在HTML表单中获取用户输入并用JavaScript动态控制复利计算循环  Win11怎么修改DNS服务器 Win11设置DNS加速网络【指南】  图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?  Laravel如何发送系统通知?(Notification渠道示例)  弹幕视频网站制作教程下载,弹幕视频网站是什么意思?  如何在腾讯云服务器快速搭建个人网站?  昵图网官方站入口 昵图网素材图库官网入口  长沙企业网站制作哪家好,长沙水业集团官方网站?  如何在Windows环境下新建FTP站点并设置权限?  Edge浏览器提示“由你的组织管理”怎么解决_去除浏览器托管提示【修复】  Laravel如何配置Horizon来管理队列?(安装和使用)  大连网站制作公司哪家好一点,大连买房网站哪个好?  Android使用GridView实现日历的简单功能  专业商城网站制作公司有哪些,pi商城官网是哪个?  Laravel如何使用Socialite实现第三方登录?(微信/GitHub示例)  Laravel如何实现API速率限制?(Rate Limiting教程)  关于BootStrap modal 在IOS9中不能弹出的解决方法(IOS 9 bootstrap modal ios 9 noticework)  高端建站三要素:定制模板、企业官网与响应式设计优化  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  Laravel用户密码怎么加密_Laravel Hash门面使用教程  如何批量查询域名的建站时间记录?  使用PHP下载CSS文件中的所有图片【几行代码即可实现】  Laravel如何自定义分页视图?(Pagination示例)  如何在IIS中新建站点并配置端口与物理路径?