进程环境

一、进程的基本概念

1、基本概念

(1)进程的定义

  进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统进行资源分配和调度运行的基本单位。
  进程和程序是有本质区别的:程序是静态的,它是一些保存在磁盘上的指令的有序集合,没有任何执行的概念;而进程是一个动态的概念,它是程序执行的过程,包括了动态创建、调度和消亡的整个过程。

(2)进程控制块(PCB)

  Linux系统通过进程控制块来描述一个进程。进程控制块包含了进程的状态信息、控制信息以及资源信息等。

1. 标识号:每个进程都有一个进程标识号(PID)和一个父进程标识号(PPID),其中PID唯一标识一个进程。另外,一个进程还有自己的用户标识号(UID)和组标识号(GID),系统通过这两个标识号判断进程对文件或设备的访问权。
2. 状态信息:一个 Linux 进程可有如下几种状态:运行、等待、停止和僵死。
3. 调度信息:调度器根据这些信息判定系统中哪个进程最迫切需要运行。
4. 有关进程间通讯的信息:系统利用这一信息实现进程间的通讯。
5. 进程与其他进程之间的关系信息:在 Linux 系统中,除根进程之外,任何一个进程都具有父进程也可能有兄弟进程或子进程。所以每个进程的PCB中包含了进程的父进程指针、和该进程具有相同父进程的兄弟进程指针以及进程的子进程指针。另外,Linux 还利用一个双向链表记录系统中所有的进程,这个双向链表的根就是 init 进程。利用这个链表中的信息,内核可以很容易地找到某个进程。
6. 时间和定时器信息:系统在这些字段中保存进程的建立时间,以及在其生命周期中所花费的 CPU 时间。Linux 也支持和进程相关的定时器,应用程序可通过系统调用建立定时器,当定时器到期,操作系统会向该进程发送sigalrm信号。
7. 文件系统信息:这类字段记录进程所打开的文件描述符信息。另外,还包含指向虚拟文件系统(Virtual File Systems,VFS)两个索引节点的指针,这两个索引节点分别是进程的主目录以及进程的当前目录。索引节点中有一个引用计数器,当有新的进程指向某个索引节点时,该索引节点的引用计数器会增加。未被引用的索引节点的引用计数为 0,因此,当包含在某个目录中的文件正在运行时,就无法删除这一目录,因为这一目录的引用计数大于0。
8. 虚拟内存与物理内存相关信息:每个进程均有自己的内存空间,为了让linux内核随时了解和控制进程的内存空间,PCB中必须保存进程内存空间的相关信息。
9. 和进程相关的上下文信息:进程上下文是用来保存进程相关的系统状态的字段。当调度程序将某个进程从运行状态切换到暂停状态时,会在上下文中保存当前的进程运行环境,包括 CPU 所有寄存器的值、进程的状态以及堆栈信息;当调度程序再次选择该进程运行时,则会从进程上下文信息中恢复进程的运行环境。

(3)进程的特征

  • 动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
  • 并发性:任何进程都可以同其他进程一起并发执行。
  • 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位。
  • 异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的,不可预知的速度向前推进。
  • 结构特征:进程有程序、数据、和进程控制块三部分组成。
  • 多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。

(4)进程的分类

  • 交互式进程:由 shell 启动,既可在前台运行,也可在后台运行,通过终端接收用户的输入,并为用户提供输出。如:vi、ps等。
  • 批处理进程:与终端没有联系,以进程列的方式,在无需人工干预的条件下完成一组批量任务。如:各种 shell 脚本程序。
  • 守护进程:有名精灵进程,是系统的后台服务进程,独立于控制中毒那,周期性地执行某种任务或等待某些事件,在系统引导时启动,在系统关闭是终止,生命周期很长。

2、进程运行状态与切换

(1)进程的三种基本状态

1. 运行状态:获得CPU的进程处于此状态,对应的程序在CPU上运行着。
2. 阻塞状态:为了等待某个外部事件的发生(如等待I/O操作的完成,等待另一个进程发来消息),暂时无法运行。也成为等待状态。
3. 就绪状态:具备了一切运行需要的条件,由于其他进程占用CPU而暂时无法运行。

(2)进程状态切换

1. 运行状态 ===> 阻塞状态:例如正在运行的进程提出I/O请求,由运行状态转化为阻塞状态。
2. 阻塞状态 ===> 就绪状态:例如I/O操作完成之后,由阻塞状态转化为就绪状态。
3. 就绪状态 ===> 运行状态:例如就绪状态的进程被进程调度程序选中,分配到CPU中运行,由就绪状态转化为运行状态。
4. 运行状态 ===> 就绪状态:处于运行状态的进程的时间片用完,不得不让出CPU,由运行状态转化为就绪状态。

在这里插入图片描述

3、进程终止方式

  有八种方式使进程终止,其中五种为正常终止:

1. 在main()函数中执行return 。
2. 调用exit()函数。
3. 调用_exit()函数 。
4. 最后一个线程从启动例程返回。
5. 最后一个线程调用函数pthread_exit()。

  异常终止有三种:

1. 调用abort函数。
2. 进程收到某个信号,而该信号使程序终止。
3. 最后一个线程对线程取消做出响应。

【return、exit和abort的区别】:

  • exit():在调用时,会做大部分清理工作,但是决不会销毁局部对象,因为没有stack unwinding。会进行的清理工作包括:销毁所有static和global对象,清空所有缓冲区,关闭所有I/O通道。
  • abort():调用时,不进行任何清理工作。直接终止程序。
  • retrun:调用时,进行stack unwinding,调用局部对象析构函数,清理局部对象。所以,用return更能避免内存泄露。

4、程序存储空间布局

在这里插入图片描述

1. 正文段:这是由cpu执行的机器指令部分。通常,正文段是可共享的,所以即使是经常执行的程序(如文本编辑程序、C编译程序、shell等)在存储器中也只需要有一个副本,另外,正文段常常是只读的,以防止程序由于意外事故而修改器自身的指令。
2. 初始化数据段:通常将此段称为数据段,它包含了程序中需赋初值的变量。
3. 非初始化数据段:通常将此段称为bss段,这一名称来源于早期汇编程序的一个操作,意思是"block started by symbol",在程序开始执行之前,内核将此段初始化为0。
4. :自动变量以及每次函数调用时所需保存的信息都存放在此段中。每次函数调用时,其返回地址、以及调用者的环境信息(例如某些机器寄存器)都存放在栈中。然后,新被调用的函数在栈上为其自动和临时变量分配存储空间。通过以这种方式使用栈,C函数可以递归调用。
5. :通常在堆中进行动态存储分配。由于历史上形成的惯例,堆位于非初始化数据段顶和栈底之间。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~青萍之末~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值