javaee论坛

普通会员

225648

帖子

335

回复

349

积分

楼主
发表于 2019-11-07 13:49:33 | 查看: 388 | 回复: 0

文章目录00.目录01.进程概述02.进程状态03.进程控制块04.进程号05.进程号相关函数06.案例实战07.附录

01.进程概述

我们平时写的C语言代码,通过编译器编译,最终它会成为一个可执行程序,当这个可执行程序运行起来后(没有结束之前),它就成为了一个进程。

程序是存放在存储介质上的一个可执行文件,而进程是程序执行的过程。进程的状态是变化的,其包括进程的创建、调度和消亡。程序是静态的,进程是动态的。

在Linux系统中,操作系统是通过进程去完成一个一个的任务,进程是管理事务的基本单元。进程拥有自己独立的处理环境(如:当前需要用到哪些环境变量,程序运行的目录在哪,当前是哪个用户在运行此程序等)和系统资源(如:处理器CPU占用率、存储器、I/O设备、数据、程序)。我们可以这么理解,公司相当于操作系统,部门相当于进程,公司通过部门来管理(系统通过进程管理),对于各个部门,每个部门有各自的资源,如人员、电脑设备、打印机等。

02.进程状态

我们现在的电脑基本上都是多任务,我们聊着QQ的时候,同时可以看着视频,这里相当于QQ和视频两个程序同时运行着(两个进程)。早期的时候,电脑的CPU是单核的(单核理论上只运行操作一个任务),那它是如何做到多任务的呢?这就涉及到进程的调度策略。现在给大家举这么一个例子,有A,B,C三个进程,在我们单CPU的情况下,每一个时刻只有一个进程在运行,如果A运行完,B运行,B运行完,C运行,C运行完,A运行,而CPU的运算速度足够快,A两次运行时间间隔足够短,从宏观上就我们就看到A,B,C好像同时运行,这就是实现单CPU运行多个任务的核心原理,通过时间片轮询调度策略实现多任务。

从上面的例子,我们可以得知,对于A进程而言,有时候在运行,有时候没有运行,两个状态不一样,所以,进程是有状态的,同时,状态是可以相互进行转换的,从执行的状态转换为不执行的状态,这里,我们可以把进程运行的整个生命周期简单划分为三种状态(实际上不指这三种状态):就绪态、执行态、等待态。

就绪态:

进程已经具备执行的一切条件,正在等待分配CPU的处理时间。

执行态:

该进程正在占用CPU运行。

等待态:

进程因不具备某些执行条件而暂时无法继续执行的状态。

这里需要注意,就绪态和等待态都是不执行,但它们是有区别的,就绪态是指满足条件,时间没到,等待态是不满足条件。

同样的,进程的这三种状态可以相互转换:

为了让大家更好地这三种状态的转换,给大家举一个买火车票的例子

Tom匆忙地赶去火车站买火车票,太着急了,到了售票厅才发现忘记带身份证,这时候,就算Tom排队也没用,因为Tom不具备买票的条件(没带身份证),这时候的Tom属于等待态。

Tom给它对象打电话,让她把身份证带过来,等会,身份证送到了,这时候,Tom可以去排队买票了,只是时间到,Tom就可以买票了,这时,Tom属于就绪态。而这过程是由等待态转换到就绪态。

等了10分钟,终于到Tom了,Tom开始买票,这时候,Tom属于执行态。而这过程是由就绪态转换为执行态。

而在买票的过程中,Tom的对象打电话给他,让Tom也帮她买一张火车票,但是,Tom没有她对象的身份证,接着,Tom继续等他对象送身份证,这时候,Tom由执行态转换为等待态。

假如是这么一种情况,Tom买火车票是给公司的同事买的(需要买100多张票),在买着票的过程中(执行态),后面还有很多人在排队,后面排队的人肯定不爽,这时售票员就说,20分钟后,如果你还没处理完,请你到后面排队。结果,Tom花了20分钟还是没有处理完,于是,乖乖地到后面重新排队,这时候,Tom由执行态转换为就绪态。

03.进程控制块

对于操作系统而言,它需要控制很多进程,同时,每个进程都有不同的状态,系统如何知道A执行完到B执行而不是C?系统如何协调控制进程呢?

当我们运行一个程序使它成为一个进程时,系统会开辟一段内存空间存放与此进程相关的数据信息,而这个数据信息是通过结构体(task_struct,打开/usr/src/linux-headers-4.15.0-30/include/linux/sched.h可以找到task_struct的定义)来存放,我们把这个存放进程相关数据信息的结构体称为进程控制块。操作系统就是通过这个进程控制块来操作控制进程。

进程控制块是操作系统中最重要的记录型数据结构。进程控制块记录了用于描述进程进展情况及控制进程运行所需的全部信息,它是进程存在的唯一标志。进程控制块里有很多信息,其中比较重要的是进程号,至于其他的一些信息我们不在这详细讨论。

04.进程号

每个进程都由一个进程号来标识,其类型为pid_t(无符号整型),进程号的范围:0~32767。进程号总是唯一的,但进程号可以重用。当一个进程终止后,其进程号就可以再次使用。

系统允许一个进程创建新进程,新进程即为子进程,子进程还可以创建新的子进程,形成进程树结构模型。整个Linux系统的所有进程也是一个树形结构。树根是系统自动构造的,即在内核态下执行的0号进程,它是所有进程的祖先。进程号为0的进程通常是调度进程,常被称为交换进程(swapper)。由0号进程创建1号进程(内核态),1号负责执行内核的部分初始化工作及进行系统配置,并创建若干个用于高速缓存和虚拟主存管理的内核线程。随后,1号进程调用execve()运行可执行程序init,并演变成用户态1号进程,即init进程。

所以,在Linux下面所有的进程都由init进程直接或者间接创建。

进程号(PID)

标识进程的一个非负整型数。

父进程号(PPID)

任何进程(除init进程)都是由另一个进程创建,该进程称为被创建进程的父进程,对应的进程号称为父进程号(PPID)。如,A进程创建了B进程,A的进程号就是B进程的父进程号。

进程组号(PGID)

进程组是一个或多个进程的集合。他们之间相互关联,进程组可以接收同一终端的各种信号,关联的进程有一个进程组号(PGID)。这个过程有点类似于QQ群,组相当于QQ群,各个进程相当于各个好友,把各个好友都拉入这个QQ群里,主要是方便管理,特别是通知某些事时,只要在群里吼一声,所有人都收到,简单粗暴。但是,这个进程组号和QQ群号是有点区别的,默认的情况下,当前的进程号会当做当前的进程组号。

Linux操作系统提供了三个获得进程号的函数getpid()、getppid()、getpgid()。

05.进程号相关函数

getpid函数

#include<sys/types.h>#include<unistd.h>pid_tgetpid(void);功能:获取本进程号(PID)参数:无返回值:本进程号

getppid函数

pid_tgetppid(void);功能:获取调用此函数的进程的父进程号(PPID)参数:无返回值:调用此函数的进程的父进程号(PPID)

getpgid函数

pid_tgetpgid(pid_tpid);功能:获取进程组号(PGID)参数:pid:进程号返回值:参数为0时返回当前进程组号,否则返回参数指定的进程的进程组号06.案例实战#include<stdio.h>#include<unistd.h>#include<sys/types.h>//pid_t--->int//pid_tgetpid(void);//pid_tgetppid(void);////uid_tgetuid(void);//uid_tgeteuid(void);//gid_tgetgid(void);//gid_tgetegid(void);intmain(void){//获取当前进程的进程号printf("getpid:%d\n",getpid());//获取当前进程的父进程号printf("getppid:%d\n",getppid());//实际用户IDprintf("getuid:%d\n",getuid());//有效的用户IDprintf("geteuid:%d\n",geteuid());//实际组IDprintf("getgid:%d\n",getgid());//有效组IDprintf("getegid:%d\n",getegid());return0;}

编译和测试结果

deng@itcast:/mnt/hgfs/LinuxHome/code/4sys/3rd/code$gcc20getpid.cdeng@itcast:/mnt/hgfs/LinuxHome/code/4sys/3rd/code$./a.outgetpid:7986getppid:7436getuid:1000geteuid:1000getgid:1000getegid:1000deng@itcast:/mnt/hgfs/LinuxHome/code/4sys/3rd/code$07.附录

7.1下载代码:

7.2参考博客:【Linux系统编程】进程介绍


您需要登录后才可以回帖 登录 | 立即注册

触屏版| 电脑版

技术支持 历史网 V2.0 © 2016-2017