Linux进程:简介与五种状态解析,深入探讨进程管理的关键技术
csdn 2023-12-04

由操作系统定义,并由操作系统所操控的一个特殊的数据结构实例叫做进程。它连接了用户代码,拥有代码运行所需的独立内存空间,在调度器的调度下使用分配给它的处理器时间片来运行。


进程及其私有内存空间

进程类似于UCOSIII中的任务,它也是用户应用程序可执行代码在系统中的一个运行过程。系统中用来表示进程身份和存在的也是控制块,只不过叫做进程控制块。进程与UCOSIII任务之间最重要的一个区别就是:进程具有自己的内存空间,进程的程序代码就运行在这个归自己所有的内存空间之中。当然,进程的控制块记录了进程的这个私有内存空间。

在UCOSIII中提到,一个任务的组成部分:任务堆栈、任务控制块、任务代码。同样Linux的进程除了这三块,同时还需要进程自己的内存空间。一个典型的进程控制块如下图所示:

进程控制块的成员mm就是指向进程内存控制块的指针,而这个进程内存控制块则关联了进程的虚拟空间结构和表示了它所占用的物理内存空间结构。

所谓进程私有内存空间,就是系统使程序运行为程序分配的程序空间。保证程序具有私有空间的基础就是虚拟内存技术。系统把程序运行所需的物理内存页框地址映射成虚拟地址,并以页表的形式提供给了程序,从而使得程序只能通过页表运行于自己的物理空间而不会干扰到系统中的其它进程。

结合前面关于Linux内存管理的讲解可知,Linux进程控制块中的mm成员如下图所示:

文章参考:【Linux】Linux虚拟内存空间描述。

另外,由于Linux进程分为用户空间和内核空间两个部分,它有时运行于用户空间,有时运行于内核空间,因此为了保护各自的现场数据,一个进程还需要两个堆栈:用户堆栈和系统堆栈,如下图所示:

最后区分一下进程和线程:在多任务系统中具有私有内存空间的正在运行的程序叫做进程,而没有私有内存空间的叫做线程。如此说来,其实UCOSIII的任务是划分到线程的。


Linux进程的状态

在Linux系统中,一个进程被创建之后,在系统中可以有下面5种状态。进程的当前状态记录在进程控制块的state成员中。

就绪状态和运行状态

就绪状态的状态标志state的值为TASK_RUNNING。此时,程序已被挂入运行队列,处于准备运行状态。一旦获得处理器使用权,即可进入运行状态。

当进程获得处理器而运行时 ,state的值仍然为TASK_RUNNING,并不发生改变;但Linux会把一个专门用来指向当前运行任务的指针current指向它,以表示它是一个正在运行的进程。

可中断等待状态

状态标志state的值为TASK_INTERRUPTIBL。此时,由于进程未获得它所申请的资源而处在等待状态。一旦资源有效或者有唤醒信号,进程会立即结束等待而进入就绪状态。

不可中断等待状态

状态标志state的值为TASK_UNINTERRUPTIBL。此时,进程也处于等待资源状态。一旦资源有效,进程会立即进入就绪状态。这个等待状态与可中断等待状态的区别在于:处于TASK_UNINTERRUPTIBL状态的进程不能被信号量或者中断所唤醒,只有当它申请的资源有效时才能被唤醒。

这个状态被应用在内核中某些场景中,比如当进程需要对磁盘进行读写,而此刻正在DMA中进行着数据到内存的拷贝,如果这时进程休眠被打断(比如强制退出信号)那么很可能会出现问题,所以这时进程就会处于不可被打断的状态下。

停止状态

状态标志state的值为TASK_STOPPED。当进程收到一个SIGSTOP信号后,就由运行状态进入停止状态,当受到一个SIGCONT信号时,又会恢复运行状态。这种状态主要用于程序的调试,又被叫做“暂停状态”、“挂起状态”。

中止状态

状态标志state的值为TASK_DEAD。进程因某种原因而中止运行,进程占有的所有资源将被回收,除了task_struct结构(以及少数资源)以外,并且系统对它不再予以理睬,所以这种状态也叫做“僵死状态”,进程成为僵尸进程。

在进程的整个生命周期中,它可在5种状态之间转换。Linux进程5种状态之间的转换关系如下图所示:

文章参考:Linux进程状态解析 之 R、S、D、T、Z、X (主要有三个状态)。

Linux有两类进程:一类是普通用户进程,它既可以在用户空间运行,又可通过系统调用进入内核空间,并在内核空间运行;另一类叫做内核进程,这种进程只能在内核空间运行。


Linux的进程控制块

在Linux中,线程、进程使用的是相同的核心数据结构。可以说,在Linux2.4的内核里只有进程,其中包含轻量进程(线程)。一个进程在核心中使用一个task_struct结构来表示,包含了大量描述该进程的信息。

Linux系统中作为进程控制块(PCB)的数据结构叫做task_struct。这个进程控制块要负责记录和跟踪进程在系统中的全部信息。

尽管task_struct数据结构庞大而复杂,但其成员可按功能分成一些组成部分。task_struct的数据结构应包含如下信息:

  • 进程的当前状态;
  • 调度信息:调度器需要知道这些信息,以便判断系统中进程的迫切度;
  • 进程标识:系统中每个进程都有一个进程标识pid;
  • 进程的通信信息:Linux支持经典的Unix IPC机制,如信号、管道和信号灯;支持系统V中的IPC机制,包括共享内存、信号灯和消息队列;
  • 进程与其他进程之间关系的信息:Linux中所有进程都是相互关联的。除了根进程外,所有进程都有一个父进程,也可能有子进程或者兄弟进程,所以每个进程的task_struct结构中要包含有指向其父进程、兄弟进程或子进程的指针;
  • 使用文件的信息:进程可自由地打开或关闭文件。进程的task_struct结构中包含一个指向文件系统及它所打开文件的指针;
  • 虚拟内存与物理内存关系的信息:所有进程都有自己的内存空间;
  • 计时器:核心需要记录进程的创建时间及其在其生命周期中消耗的CPU的时间;
  • 处理器中与进程有关的信息。

Linux可以管理512个进程,每个进程的进程控制块指针都存放在一个数组中。为了使系统可快速访问正在运行的进程,Linux系统把当前运行进程的指针存放在指针变量current中。

进程控制块task_struct的部分定义如下:

struct task_struct {
	volatile long state;	/* 进程的状态 */

	unsigned long flags;	/* 与管理有关的状态信息 */

	int prio, static_prio, normal_prio;        //优先级,静态优先级

	struct list_head tasks;            //进程链表

	struct list_head ptrace_children;
	struct list_head ptrace_list;

	struct mm_struct *mm, *active_mm;        //指向进程存储空间的指针

	pid_t pid;                     //进程的pid
	pid_t tgid;

	struct task_struct *real_parent;     /* 真父进程指针 */
	struct task_struct *parent;         /* 父进程指针 */

	struct list_head children;	        /* 子进程链表 */
	struct list_head sibling;	        /* 兄弟进程链表 */
	struct task_struct *group_leader;	        /* threadgroup leader */

	struct timespec start_time; 		/* monotonic time */
	struct timespec real_start_time;	/* boot based time */

	struct thread_struct thread;

        unsigned long rt_priority;            //实时优先级

	struct fs_struct *fs;                //进程所在文件目录
	struct files_struct *files;            //进程打开文件信息
    
        struct dentry *proc_dentry;            //proc文件的dentry
        struct backing_dev_info *backing_dev_info;

	struct signal_struct *signal;                //信号
	struct sighand_struct *sighand;

        ...

};

系统中把所有进程控制块组织为如下图所示的双向链表:


声明: 本文转载自其它媒体或授权刊载,目的在于信息传递,并不代表本站赞同其观点和对其真实性负责,如有新闻稿件和图片作品的内容、版权以及其它问题的,请联系我们及时删除。(联系我们,邮箱:evan.li@aspencore.com )
0
评论
  • 相关技术文库
  • 单片机
  • 嵌入式
  • MCU
  • STM
  • 基于C51单片机实现汽车座椅自动控制系统的软硬件设计

    引言 随着人们生活水平的提高,对汽车座椅的舒适性要求也越来越高,要求对汽车座椅地调节能够更加简单、方便、快捷。目前,汽车座椅位置的调节多采用基于手动调节方式的机械和电动控制两种方式。汽车座椅位置的调节...

    前天
  • MCS51单片机程序设计时堆栈的计算方法解析

    用C语言进行MCS51系列单片机程序设计是单片机开发和应用的必然趋势。Keil公司的C51编译器支持经典8051和8051派生产品的版本,通称为Cx51。应该说,Cx51是C语言在MCS51单片机上的扩展,既有C语言的共性,又有它自己...

    前天
  • 51单片机定时器工作原理及用法

    TMOD : 控制定时器的工作方式。8个bit,高四位 bit 控制 T1,、低四位 bit 控制 T0。因为定时器有4种工作方式;TMOD = 0x00(工作方式0),TMOD = 0x01(工作方式0),TMOD = 0x02(工作方式2),TMOD = 0x03(工作方式3)。...

    前天
  • 51单片机学习单片机之路总结

    学习单片机有一学期了,现在也由51转到STM32了。一直想对51的学习做一个总结。也希望对别人有一些启发。也给后学者提供一些建议。当然本文是我对自己学习过程的总结,若有不对的地方,还请高手指出。 我想,再看本...

    前天
  • hot51增强型单片机开发板原理图

    功能要求: 一):绿灯25s倒计时,绿灯过度红灯有5s黄灯时间,红灯25s后直接跳绿灯。 二):按键按下模拟闯红灯输入,产生5s蜂鸣器鸣叫。 开发环境: 软件:Keil uVision4 硬件:HOT51增强型单片机开发板 程序代码:...

    07-01
  • 51单片机的延时子程序

    延时程序在单片机编程中使用非常广泛,但一些读者在学习中不知道延时程序怎么编程,不知道机器周期和指令周期的区别,不知道延时程序指令的用法, ,本文就此问题从延时程序的基本概念、机器周期和指令周期的区别和联系...

    07-01
  • 什么是Flash盘?Flash盘的结构是什么样的?

    Flash是大家常使用的存储之一,对于Flash,大家或多或少有所了解。上篇文章中,小编对Flash闪存的类型有所介绍。为继续增进大家对Flash的认识,本文将对Flash盘、Flash盘结构以及Flash读写操作予以介绍。如果你对本...

    07-01
  • 深谈嵌入式系统,嵌入式系统是如何组成的?

    嵌入式系统在生活中有诸多应用,大家对于嵌入式系统或多或少有所耳闻。在前两篇文章中,小编对嵌入式系统进行过详细介绍。为继续增进大家对嵌入式系统的认识,本文将对嵌入式系统的组成加以说明。如果你对嵌入式系...

    06-27
  • 嵌入式系统秘籍共享,最全嵌入式系统解析

    嵌入式系统的应用十分广泛,因此越来越多的人学习嵌入式系统。由此,在学习嵌入式系统之前,我们应当对嵌入式系统具备一些认识。所以在本文余下部分,小编将对嵌入式系统进行全面解析。如果你对嵌入式系统具有兴趣...

    06-27
  • 51单片机超声波测距程序详解

    51单片机超声波测距程序详解 超声波四通道测距:超声波测距实现分为三大块: 其一是12864带字库的液晶驱动程序: 代码如下: /////////////////12864驱动程序/////////////////////////// //1写数据 void WriteDat...

    06-25
  • 51系列单片机的引脚图

    51系列单片机的引脚图 端子介绍 l P0.0~P0.7 P0口8位双向口线(在引脚的39~32号端子)。 l P1.0~P1.7 P1口8位双向口线(在引脚的1~8号端子)。 l P2.0~P2.7 P2口8位双向口线(在引脚的21~28号端子)。 l P3.0~P3.7 P2口8...

    06-25
  • 51单片机串口通信需要加超时中断吗?

    接收数据时,超过一定时间就算出错. 这个超时的时间是单片机自己算出的吗?超时的时间是由编程序的人定的,他定多长就多长从一段程序开始 实现电脑向 单片机发送一些数据,单片机返回Iget +数据 #include #define u...

    06-25
下载排行榜
更多
评测报告
更多
广告