第一次作业:Linux2.6源码分析进程模型

1.进程的定义

从系统允许多个程序同时进入CPU那一天开始,我们才有了进程,进程的出现,解决了程序并发执行时对系统资源共享的描述问题,同时顺路解决了程序执行时动态特征的描述问题。

进程:一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统进行资源分配和调度运行的基本单位

进程四要素:

1.有一段程序供其执行,该程序不一定是一个进程独享,也可以和其他进程共享。

2.有进程专用的内核空间堆栈。

3.在内核中有一个名为“进程控制块”的task_struct,内核通过结构对进程进行调度控制。

4.有独立的用户空间。有独立的用户空间的是进程,有共享的用户空间的是用户线程,没有用户空间的是内核线程。

2.操作系统是怎么组织进程的

进程控制块PCB(Process Control Block)是进程存在和运行的唯一标志,在Linux中用task_struct这个结构体来表示。这个结构体中有很多数据项。

2.1进程状态

task_struct中用一个长整形state volatile long state; 表示进程的状态。

在linux中有四种基本的进程状态:

(1)就绪态(TASK_RUNNING):包括了运行态的进程。这是为了方便管理,因为任意时刻处于就绪态的进程最多只有一个。

(2)等待(睡眠)态:又被分为两种

i.浅度睡眠态(TASK_INTERRUPTIBLE): 在两种情况下被唤醒:

1.当等待的资源满足时。

2.其它进程通过信号或时钟中断唤醒。

ii.深度睡眠态(TASK_UNINTERRUPTIBLE):只能等到等待的资源满足时才被唤醒,而不能被其它进程唤醒

(3)暂停状态(TASK_STOPPED):收到以下几种信号,进程进入暂停状态:

i.SIGSTOP------------------停止进程执行

ii。SIGTSTP-----------------从终端发来信号停止进程

iii。SIGTTIN------------------来自键盘的中断

iv。SIGTTOU----------------后台进程请求输出。

(4)僵死状态(TASK_ZOMBIE):进程已结束且释放大部分资源,但尚未释放其PCB

2.2进程标识符

每个进程都有一个非负的唯一进程ID(PID)。虽然是唯一的,但是PID可以重用,当一个进程终止后,其他进程就可以使用它的PID了。

PID为0的进程为调度进程,该进程是内核的一部分,也称为系统进程;PID为1的进程为init进程,它是一个普通的用户进程,但是以超级用户特权运行;PID为2的进程是页守护进程,负责支持虚拟存储系统的分页操作。

linux用一个32位无符号整形pid来简单的标识一个进程,用uid和gid分别来标识进程所属的用户和组 pid_t pid; uid_t uid; gid_t gid;  。

2.3内核堆栈

进程通过alloc_thread_info函数分配它的内核栈,通过free_thread_info函数释放所分配的内核栈.  void*stack;

2.4进程链表

每个task_struct中都有一个tasks的域来连接到进程链表上去。

struct task_struct{
  ...
  struct list_head tasks;
  ...
  char comm[TASK_COMM_LEN];//可执行程序名
  ...
};  

2.5哈希表

进程链表是将所有的进程连接到一个链表上去,所以查找一个进程的时间复杂度是O(N),效率很低。为此,使用哈希表来提高查找的效率。

哈希表的定义 static struct hlist_head *pid_hash;

哈希函数对查找至关重要,好的哈希函数能减少冲突发生概率。

#define pid_hashfn(nr, ns)      \
        hash_long((unsigned long)nr + (unsigned long)ns, pidhash_shift)  
#define hash_long(val, bits) hash_32(val, bits)
static inline u32 hash_32(u32 val, unsigned int bits)
{
        /* On some cpus multiply is faster, on others gcc will do shifts */
        u32 hash = val * GOLDEN_RATIO_PRIME_32;  

        /* High bits are more random, so use them. */
        return hash >> (32 - bits);
}  
/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
#define GOLDEN_RATIO_PRIME_32 0x9e370001UL  

2.6就绪队列

task_struct定义了一个连接到就绪队列的域run_list,同样,内核中有一个就绪队列头runqueue_head。

struct sched_rt_entity {
        struct list_head run_list;
        ....
};
struct task_struct
{
        ....
        struct sched_rt_entity rt;
        ......
};  

2.7等待队列

等待队列的数据结构:

typedef struct __wait_queue wait_queue_t;
struct __wait_queue {
        unsigned int flags;
#define WQ_FLAG_EXCLUSIVE       0x01
        void *private;
        wait_queue_func_t func;
        struct list_head task_list;
};  

等待队列列头:

struct __wait_queue_head {
        spinlock_t lock;
        struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;  

3.进程状态如何转换

在第二条中已经将进程状态做了分类,详细转换看大佬画的下图。

下附一张自己画的简图

4.进程是如何调度的

4.1进程调度优先级:

 intprio, static_prio, normal_prio;

    unsignedint rt_priority;

    conststruct sched_class *sched_class;

    structsched_entity se;

    structsched_rt_entity rt;

4.2优先级定义:

 #defineMAX_USER_RT_PRIO     100

    #defineMAX_RT_PRIO      MAX_USER_RT_PRIO

    #defineMAX_PRIO     (MAX_RT_PRIO+ 40)

    #defineDEFAULT_PRIO     (MAX_RT_PRIO + 20)

实时优先级范围是0到MAX_RT_PRIO-1(即99),而普通进程的静态优先级范围是从MAX_RT_PRIO到MAX_PRIO-1(即100到139)。值越大静态优先级越低。

4.3调度策略:

 #defineSCHED_NORMAL     0

    #defineSCHED_FIFO       1

    #defineSCHED_RR     2

    #defineSCHED_BATCH      3

    /* SCHED_ISO:reserved but not implemented yet */

    #defineSCHED_IDLE       5

    /* Canbe ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */

    #defineSCHED_RESET_ON_FORK     0x40000000

SCHED_NORMAL用于普通进程,通过CFS调度器实现。

SCHED_BATCH用于非交互的处理器消耗型进程。

SCHED_IDLE是在系统负载很低时使用。

SCHED_FIFO:先入先出调度算法。

SCHED_RR:时间片轮流调度算法。

 4.4调度时机

主动式:

当进程等待资源停止运行的时候,会处于睡眠状态,这时候直接调用schedule()请求调度,让出cpu。

例:

 current->state= TASK_INTERRUPTIBLE

    schedule();

使用指向当前进程状态的指针,将state改为可中断睡眠状态,然后调用schedule(),这样cpu就会调度其他资源执行。

抢占式调度:

首先,抢占的含义,当我们一个进程A在执行的时候,B进程在执行一项更加重要的任务,这时候就需要把cpu的资源让给B,如果A不能像上面一样主动地让出,那么B就去抢占cpu的资源。

4.5调度步骤

第一步:清理当前运行中的进程的一些资源。

第二步:根据调度策略选择一个运行的进程。

第三步:设置新的进程运行环境,例如堆栈,sp等。

第四步:进程上下文切换,退出A,切到B。

 5.自己对该操作系统进程模型的看法

虽然现在Linux已经是4.x时代了,但是2.6时代的跨度很大,要详细研究问题挺多的。自知才疏学浅,只粗略的学习了其进程模型,觉得其调度器的更改是一个很大改进。

Linux 一开始,普通进程和实时进程都是基于优先级的一个调度器, 实时进程支持 100 个优先级,普通进程是优先级小于实时进程的一个静态优先级,所有普通进程创建时都是默认此优先级,但可通过 nice() 接口调整动态优先级(共40个). 实时进程的调度器比较简单,而普通进程的调度器,则历经变迁。2.6 时代开始支持(2002年引入)O(1) 调度器。顾名思义,此调度器为O(1)时间复杂度。该调度器修正之前的O(n) 时间复杂度调度器,以解决扩展性问题。为每一个动态优先级维护队列,从而能在常数时间内选举下一个进程来执行。

6.参考资料:

https://blog.csdn.net/deep_l_zh/article/details/48346287

https://www.cnblogs.com/jacklu/p/5317406.html

https://blog.csdn.net/kklvsports/article/details/52268085

https://www.zhihu.com/question/35484429

原文地址:https://www.cnblogs.com/sky520/p/8972433.html

时间: 2024-07-31 06:15:36

第一次作业:Linux2.6源码分析进程模型的相关文章

第一次作业:深入源码分析进程模型(Linux kernel 2.6.32)

1.前言 本文基于Linux 2.6.32分析其进程模型,包括进程的概念.组织.转换.调度等内容,帮助对操作系统课程及Linux相关知识的理解和学习. 附Linux Kernel 2.6.32源码下载地址: https://mirrors.edge.kernel.org/pub/linux/kernel/v2.6/linux-2.6.32.tar.gz 2.进程的概念 2.1什么是进程? 在正式开始结合源代码分析进程模型之前,我们首先需要搞清楚进程的究竟是什么. 维基百科上对于进程的定义如下:

第一次作业:深入源码分析进程模型(linux)

一.什么是进程 计算机上有许多可以运行的软件,其中也包括操作系统,这些软件运行时,就产生了一个或多个进程. 二.Linux系统中进程的组织与转换 1>Linux中进程的描述符(即用来描述一个进程的结构体) struct task_struct { ...... volatile long state; // 描述进程的运行状态 void *stack; // 指向内核栈 struct list_head tasks; // 用于加入进程链表 ...... struct mm_struct *mm

第一次作业:深入源码分析进程模型

前言:          这是一篇关于linux操作系统的简单介绍.linux本身不能算是操作系统,只是一个内核,基于linux内核的操作系统有很多,比如流行的android,ubuntu,红旗linux等等.Linux以它的高效性和灵活性著称.它能够在PC计算机上实现全部的Unix特性,具有多任务.多用户的能力.Linux是在GNU公共许可权限下免费获得的,是一个符合POSIX标准的操作系统.Linux操作系统软件包不仅包括完整的Linux操作系统,而且还包括了文本编辑器.高级语言编译器等应用

第一次作业:基于Linux0.01深入源码分析进程模型

一.前言 本文主要基于Linux0.01源代码分析进程模型.Linux 0.01虽然是Linux的第一个发行版本,但是却基本具备了操作系统中最重要的组成部分,同时Linux 0.01只有8500行左右的代码,对于初学者而言学习起来比较简单一点. Linux 0.01源代码下载地址: https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/ 二.进程的定义 进程是程序执行的基本单位.(其中,进程和程序的区别:程序指的是由若干函数组成的可执

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

1.前言 本文主要基于Linux 2.6源代码分析进程模型.源代码下载地址:https://elixir.bootlin.com/linux/v2.6.39/source 2.进程 定义:进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础. 3.Linux系统进程的组织 进程是由进程控制块(PCB).程序段.数据段三部分组成. 3.1 进程控制块 进程控制块(Processing Control Block),是操作系统核心中一种数据结构

第一次作业:深入源码分析xv6进程模型

1.进程 1.1 进程的概念 1) 狭义定义:进程是正在运行的程序的实例. 2) 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动.它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元. 1.2 进程的组成 1.3 进程控制块 引用来自:https://blog.csdn.net/hgnuxc_1993/article/details/54847732 2.操作系统如何组织进程 在这里把组织进程理解为管理和控制进程 操作系统通过P

深入源码分析进程模型

1.操作系统是怎么组织进程的 struct task_struct { ...... /* 进程状态 */ volatile long state; /* 指向内核栈 */ void *stack; /* 用于加入进程链表 */ struct list_head tasks; ...... /* 指向该进程的内存区描述符 */ struct mm_struct *mm, *active_mm; ........ /* 进程ID,每个进程(线程)的PID都不同 */ pid_t pid; /* 线

第一次作业 基于Linux 0.12的进程模型分析

作业内容 挑选一个开源的操作系统,深入源码分析其进程模型,具体包含如下内容: 操作系统是怎么组织进程的 进程状态如何转换(给出进程状态转换图) 进程是如何调度的 谈谈自己对该操作系统进程模型的看法 1.操作系统是怎么组织进程的 1.1什么是进程 程序是一个可执行的文件,而进程是一个执行中的程序实例.Linux操作系统上利用分时技术,可同时运行多个进程.利用分时技术,在Linux操作系统上同时可以运行多个进程.分时技术的基本原理是把CPU的运行时间划分成一个个规定长度的时间片,让每个进程在一个时间

Netty源码分析--内存模型(上)(十一)

前两节我们分别看了FastThreadLocal和ThreadLocal的源码分析,并且在第八节的时候讲到了处理一个客户端的接入请求,一个客户端是接入进来的,是怎么注册到多路复用器上的.那么这一节我们来一起看下客户端接入完成之后,是怎么实现读写操作的?我们自己想一下,应该就是为刚刚读取的数据分配一块缓冲区,然后把channel中的信息写入到缓冲区中,然后传入到各个handler链上,分别进行处理.那Netty是怎么去分配一块缓冲区的呢?这个就涉及到了Netty的内存模型. 当然,我们在第一节的时