这次作业主要基于Linux-0.12的源代码,分析Linux是如何组织进程,进程的状态之间是如何转换,以及进程是如何调度的。

一. 进程的概念:

  1.进程就是:程序在数据集合上的一次运行过程,是系统进行资源分配和调度的独立单位。

  2.对进程的静态描述为:是一个数据集合,以及在其上运行的程序。

  3.我本来认为进程与程序是差不多的东西,但发现他们其实并不一样,进程是一个动态的概念,不同于程序又依赖于程序,既有联系又有区别,进程具备程序不具备的特征,比如:

   1).动态特征:进程具有生命周期,创建之后才产生,调度时运行,得不到资源就发生阻塞,撤销之后就消亡。进程本身就是一个执行过程,程序,却仅仅是个静态文本(指令合集);

   2).并发特征:多个进程实体,同存于主存中,能在一段时间内同时运行。由此可见进程的并发特征是其第二基本特征,程序不具备并发性;

   3).独立特征:进程是系统进行资源分配和调度的一个基本单位,程序段是不可做为独立单位接收资源分配和调度的;

   4).结构特征(静态特征):为了描述进程的运动变化过程系统为每一个进程配置了一个进程控制块(PCB:Process Control Block),这样静态的看或从结构上看,进程就由正文段,数据集合(结构)以及PCB三部分组成,一般将这三部分组成结构成为进程映像:

进程映像

  

   5). 异步特征:各进程按照其各自独立的,不可预知的速度向前推进。

  In a word, 进程 == 可以和其他程序并发执行的 程序的 一次执行。

二. Linux操作系统是怎么组织进程的:

  1. Linux是一个多任务的开放式操作系统,进程就是许多分离的任务,每一个进程彼此独立,并通过进程间的通信机制实现进程之间的同步与互斥。在Linux系统中,进程与任务是相同的概念。

  2. 系统中有许多进程,Linux要对其进行管理和调度,就要通过存放在系统数据段中的进程控制信息,其中最重要的就是task_struct数据结构。

      • 正文段:是具有可再入性的代码组成的程序(可再入程序也称纯代码,可同时被多个进程或程序所共享的程序),因此对用不同的数据集,可以构成不同的进程,所以正文段是可以调用但是不可以修改的,一般情况下是由系统程序组成。
      • 进程控制块(PCB):PCB中记录了用于描述进程情况及控制进程运行所需的全部属性信息。系统通过PCB感知进程的存在,是进程进行控制存在的唯一标识。系统根据PCB来对并发执行的进程进行控制和管理。系统会在创建进程时就创建该进程的PCB,在撤销一个进程时就撤销其PCB。当操作系统要调用进程执行时。需要从该进程的PCB中查询其现行状态机优先级等调度参数,在调度到某进程后,要根据PCB中保存的处理机状态信息去设置进程回复运行的现场,并根据其PCB中的进程和数据的内存地址来找到程序和数据;进程在执行过程中,当需要与其它进程通信时,也需要访问其PCB;当进程因某种原因而暂停执行时,需要将断点的现场信息保存在其PCB中。
      • 数据集合:由数据所组成的集合。 
PCB通常包含的内容
进程描述信息 进程控制和管理信息 资源分配清单 处理机相关信息
进程标识符(PID) 进程当前状态 代码段指针 通用寄存器值
用户标识符(UID) 进程优先级 数据段指针 地址寄存器值  

  3. 在linux内核代码定义了task_struct 数据结构,包含了一个进程所有的信息:

 struct task_struct {
/* these are hardcoded - don't touch */
long state; /* -1 unrunnable, 0 runnable, >0 stopped */
long counter;
long priority;
long signal;
struct sigaction sigaction[];
long blocked; /* bitmap of masked signals */
/* various fields */
int exit_code;
unsigned long start_code,end_code,end_data,brk,start_stack;
long pid,pgrp,session,leader;
int groups[NGROUPS];
/*
* pointers to parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->p_pptr->pid)
*/
struct task_struct *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
unsigned short uid,euid,suid;
unsigned short gid,egid,sgid;
unsigned long timeout,alarm;
long utime,stime,cutime,cstime,start_time;
struct rlimit rlim[RLIM_NLIMITS];
unsigned int flags; /* per process flags, defined below */
unsigned short used_math;
/* file system info */
int tty; /* -1 if no tty, so it must be signed */
unsigned short umask;
struct m_inode * pwd;
struct m_inode * root;
struct m_inode * executable;
struct m_inode * library;
unsigned long close_on_exec;
struct file * filp[NR_OPEN];
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
struct desc_struct ldt[];
/* tss for this task */
struct tss_struct tss;
}; 

三. 进程状态如何转换(给出进程状态转换图):

  1. 在多道程序系统中,多个进程都要在CPU上运行,有时还要申请使用其他资源,由于资源的宝贵性,使得并非每个进程都能立即得到资源,从而导致进程之间的竞争(竞争是由两个以上进程以显式或隐式的方式共享资源而引起的状态)。

  2. 一般情况下进程有三种状态,就绪(资源,CPU),运行(资源,CPU),阻塞(资源,CPU)。

  3. Linux在每个进程的task_struct结构中,定义了state域来描述进程的调度状态,共有五种,定义如下:

 #define TASK_RUNNING        0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#define TASK_ZOMBIE 3
#define TASK_STOPPED 4
#define TASK_RUNNING        0

    1)运行态或可运行态:已经占有CPU正在运行,或者正处于运行队列中,等待着系统的进程调度程序schedule()将CPU分配给它。系统中有一个运行队列run_queue,容纳了所有处于可运行状态的进程,当前正在运行的进程也一直处于该队列中,由全局变量current指向。

    *该状态是Linux与一般操作系统的区别,在其他操作系统中,只有正在使用CPU的进程才处于运行状态,其他都处于就绪状态。

#define TASK_INTERRUPTIBLE    1

    2)进程可中断的睡眠态:因等待某一事件或某种资源而加入等待队列,等待资源有效时被唤醒。

#define TASK_UNINTERRUPTIBLE    2

    3)进程不可中断的睡眠态:此时的进程因为硬件条件的不满足而睡眠,处于等待队列中,在任何情况下都不能被打断,除非通过特定的方式来唤醒,比如通过唤醒函数wake_up()等。

#define TASK_ZOMBIE        3

    4)进程僵死状态(终结态):当进程使用系统调用exit自我消亡时,将state设为此状态。发送信号给父进程并释放占有的系统资源,但它的task_struct结构仍未释放。父进程通过系统调用wait收集其中包含的出口码及一些计时信息后,释放他的task_struct结构。

#define TASK_STOPPED        4

    5)进程被暂停运行状态:进程暂时停止运行来接受某种处理,通过其他进程的信号才能唤醒。

 4. 进程状态的转换:

    1).Linux中用户进程是由父进程执行系统调用fork()或者clone()等创建的。这些系统调用都通过调用do_fork()函数来完成子进程的创建。do_fork()函数创建一个新进程,为其创建一个task_struct结构,继承父进程现有的资源,子进程创建后的状态为TASK_RUNNING态,父进程将它挂入到运行队列run_queue中,等待处理器的分配。

    2).获得CPU而正在运行的进程如果申请不到某个资源,则调用函数sleep_on()或interruptible_sleep_on()转入睡眠,其task_struct结构从run_queue队列移入xiangying的等待队列。如果调用sleep_on(),则其状态转入不可中断的睡眠态TASK_UNINTERRUPTIBLE,如果调用interruptible_sleep_on(),则其状态转入可中断睡眠态TASK_INTERRUPTIBLE 。无论转入哪种睡眠状态,都将调用schedule()函数把睡眠进程释放的CPU重新分配给run_queue队列中的某个可运行的进程。

    3).转入TASK_INTERRUPTIBLE的睡眠进程在它申请的资源有效时将被唤醒(被某函数,信号或者中断),而转入TASK_UNINTERRUPTIBLE的睡眠进程只有在它申请的资源有效时被唤醒,不能被信号,定时器中断唤醒。这些被唤醒的进程都转入TASK_RUNNING状态, 并进入run_queue队列。

    4).当进程收到暂停或停止信号时,状态转入TASK_STOPPED ,暂停运行,CPU重新分配给run_queue队列中的其他可运行进程,只有通过其他进程发送恢复信号,才能把TASK_STOPPED 进程唤醒,重新进入run_queue队列。

    5).当进程运行完成,执行系统调用exit()或do_exit()时,进程转入僵死态TASK_ZOMBIE,释放所占有的系统资源,同时启动schedule()把CPU分配给run_queue队列中的其他进程。

  5. 进程状态转换图:

四. 进程是如何调度的:

  1. Linux主要采用了基于优先权的时间片轮转法为进程分配CPU。按照这种调度方法,系统给每个运行进程分配一个时间片,而优先权的大小又决定了哪个进程被调度运行(Linux的进程调度并不局限于某一种调度策略,它融合了基于优先权的轮转法调度,基于优先权的先进先出调度以及多级反馈轮转调度的策略,具有很高的综合性)。 

  2.

       long priority;

    1). 进程(实时和普通)的优先级反映了进程相对于其他进程的可选择度,也是系统每次允许进程运行的时间。

       long counter;

    2). 进程运行所剩余的时间片,每次时钟中断发生时,值-1,直到为0,counter = 0表示进程的时间片已经用完,要停止运行。

  3. Linux进程调度时机主要有:

1). 进程状态转换的时时。如进程终止、进程睡眠;

2). 当前进程的时间片用完时(current->counter=0),要重新选择一个进程;

3). 设备驱动程序,直接调用schedule();

4). 进程从中断、异常及系统调用处理后返回到用户态时。

  4. Linux-0.12 schedule()如下:

void schedule(void)
{
int i,next,c;
struct task_struct ** p;
/*有信号来时,唤醒进程*/
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p) {
if ((*p)->timeout && (*p)->timeout < jiffies) {
(*p)->timeout = ;
if ((*p)->state == TASK_INTERRUPTIBLE)
(*p)->state = TASK_RUNNING;
}
if ((*p)->alarm && (*p)->alarm < jiffies) {
(*p)->signal |= (<<(SIGALRM-));
(*p)->alarm = ;
}
if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
(*p)->state==TASK_INTERRUPTIBLE)
(*p)->state=TASK_RUNNING;
}
while () {
c = -;
next = ;
i = NR_TASKS;
p = &task[NR_TASKS];
while (--i) {
if (!*--p)
continue;
if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
c = (*p)->counter, next = i;
}
if (c) break;
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p)
(*p)->counter = ((*p)->counter >> ) +
(*p)->priority;
}
switch_to(next);
}

五. 我对Linux操作系统进程模型的看法:

  Linux支持多进程,进程控制块task_struct结构包括进程标识,进程状态,进程调度,进程指针,文件管理和虚存管理等,Linux对普通进程采用的是优先级调度策略。尽量公平合理的进行各进程之间的调度。

六.  参考资料:

https://blog.csdn.net/hgnuxc_1993/article/details/54847732

http://www.docin.com/p-820504201.html

https://blog.csdn.net/songjinshi/article/details/23262923

操作系统原理与分析(第一版);曹聪,范廉明 著;科学出版社

第一次作业:基于Linux-0.12的进程分析的更多相关文章

  1. Linux 0.12 内核管理存储器

    Linux 0.12 内核管理存储器 其分段,用分段的机制把进程间的虚拟地址分隔开. 每一个进程都有一张段表LDT.整个系统有一张GDT表.且整个系统仅仅有一个总页表. 其地址翻译过程为: 程序中给出 ...

  2. 第一次作业:基于Linux 4.5的进程模型与调度器分析

    1.操作系统是怎么组织进程的? 1.1什么是线程,什么是进程: 刚接触时可能经常会将这两个东西搞混.简单一点的说,进程是一个大工程,线程则是这个大工程中每个小地方需要做的东西(在linux下看作&qu ...

  3. 《linux 内核全然剖析》编译linux 0.12 内核 Ubuntu 64bits 环境

    我×.. . 最终好了,大概3 4个小时吧...各种毛刺问题.终究还是闯过来了.. .. ubuntu2@ubuntu:~/Downloads/linux-0.00-050613/linux-0.00 ...

  4. Linux内核的idle进程分析

    1. idle是什么 简单的说idle是一个进程,其pid号为 0.其前身是系统创建的第一个进程.也是唯一一个没有通过fork()产生的进程. 在smp系统中,每一个处理器单元有独立的一个执行队列,而 ...

  5. 转:基于 linux 平台的 libpcap 源代码分析

    libpcap 是 unix/linux 平台下的网络数据包捕获函数包,大多数网络监控软件都以它为基础.Libpcap 可以在绝大多数类 unix 平台下工作,本文分析了 libpcap 在 linu ...

  6. iOS开发--基于AFNetWorking3.0的图片缓存分析

    图片在APP中占有重要的角色,对图片做好缓存是重要的一项工作.[TOC] 理论 不喜欢理论的可以直接跳到下面的Demo实践部分 缓存介绍 缓存按照保存位置可以分为两类:内存缓存.硬盘缓存(FMDB.C ...

  7. 【转载】基于AFNetWorking3.0的图片缓存分析

    原文出处: Yasin的简书 理论 不喜欢理论的可以直接跳到下面的Demo实践部分 缓存介绍 缓存按照保存位置可以分为两类:内存缓存.硬盘缓存(FMDB.CoreData…).我们常说的网络请求缓存包 ...

  8. 基于Linux平台的libpcap源码分析和优化

    目录 1..... libpcap简介... 1 2..... libpcap捕包过程... 2 2.1        数据包基本捕包流程... 2 2.2        libpcap捕包过程... ...

  9. 第一次作业:基于Linux操作系统深入源码进程模型分析

    1.Linux操作系统的简易介绍 Linux系统一般有4个主要部分:内核.shell.文件系统和应用程序.内核.shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序.管理文件并使 ...

随机推荐

  1. JS实现填报时对修改过的单元格进行标识

    1. 描述 在填报预览时,对单元格编辑后,其左上角有个红色标记,但非常不明显,用户很难注意到.有没有什么好的办法,对单元格操作后,将其做较明显的特殊标记处理,方便用户识别呢? 如图所示:对单元格进行操 ...

  2. Keras vs. PyTorch in Transfer Learning

    We perform image classification, one of the computer vision tasks deep learning shines at. As traini ...

  3. oracle exp dmp

    exp help=yconn scott/tiger;select * from tab;create table student(sno int, sname varchar2(10), sage ...

  4. eclipse安装Android插件

    1.首先下载Eclipse for android,点击进入.下载这个版本可以省去ADT配置() 2.下载符合你电脑的版本 2.现在Android SDK,地址:http://tools.androi ...

  5. Mac下驱动BCM20702A0 USB蓝牙

    偶然高了一个USB蓝牙,查到Mac下能识别,无法驱动,就去找了一下.方法很简单,就是把蓝牙的PID和VID加入到驱动里边去,具体方法和步骤如下: 1. 进入到/System/Libary/Extens ...

  6. Mysql中的delimiter详解

    初学mysql时,可能不太明白delimiter的真正用途,delimiter在mysql很多地方出现,比如存储过程.触发器.函数等. 学过oracle的人,再来学mysql就会感到很奇怪,百思不得其 ...

  7. Vue-学习。

    ---恢复内容开始--- Vue.js 与 Angular.js 非常相似,只要学过了Angular.js然后在学Vue.js就非常的简单. 什么是Vue? 相比Angularjs和ReactJS,V ...

  8. ubuntu-15.04-desktop-amd64想要安装KDE桌面,结果出现如下问题

    The following packages have unmet dependencies: kubuntu-desktop : Depends: ark but it is not going t ...

  9. [WINCE|VS2008] 用在PC上调试WINCE程序

    http://www.danielmoth.com/Blog/deploy-to-my-computer.aspx 作者:The Moth 步骤: 1. 在VS2008中打到 Device Optio ...

  10. 对MBProgressHUD进行二次封装并精简使用

    对MBProgressHUD进行二次封装并精简使用 https://github.com/jdg/MBProgressHUD 几个效果图: 以下源码是MBProgressHUD支持最新的iOS8的版本 ...