进程调度模拟

11 篇文章 1 订阅
5 篇文章 1 订阅

        进程调度就是在所有可运行的进程之间分配CPU资源,它使得在单个CPU上并发执行多个进程成为可能。本文通过java模拟时间片轮转算法,以具象化进程调度。进程是操作系统中一个重要的抽象,通过进程调度和虚拟内存机制实现了CPU和内存的虚拟化。在每个进程看来,自己是独占CPU和内存的。

        下面看一下进程调度的大致原理,每个进程是程序的执行实体,相当于程序执行的容器。在进程执行时,进程有自己的执行环境,包括进程本身的状态和CPU状态,进程本身状态有代码、数据以及堆栈等,CPU状态就是相关寄存器的状态。在进程调度时,需要完成进程执行环境的切换,也就是上下文切换。

        时间片就是进程在被抢占之前持续运行的时间。当一个进程的时间片耗尽后,调度程序会暂停该程序的执行,然后选择其他的进程抢占CPU。由于大部分OS的时间片都很短(基本上10ms),所以在人们看来这些进程是同时执行的。

        调度程序维护者一个运行队列(Run Queue),包含所有处于可运行状态(TASK_RUNNING)的进程(在Linux中的CFS调度器,运行队列被组织成红黑树,按照进程的已运行时间排序)。调度程序就是在运行队列中,选择合适的进程抢占CPU。

        当进程等待某个事件发生时会被阻塞,比如等待IO操作完成或是获取锁失败时,此时进程处于阻塞状态(TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE)不可能被调度占有CPU。进程的阻塞是通过等待队列(Wait Queue)实现的。每个被等待的事件都有自己的等待队列,比如一个锁或是文件描述符。进程执行阻塞操作时:

        1. 将自己添加到相应事件的等待队列,当该事件发生时,队列上的所有进程会被唤醒,这个唤醒操作在其他地方执行。

        2. 将进程的状态更新为阻塞状态(TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE)。

        3. 调用schedule函数以调度其他进程执行。

        唤醒操作很简单,当事件发生时,会将等待队列上的进程的状态修改为运行态(TASK_RUNNING),以便调度程序可以调度它执行。

        还有一个重要的问题就是调度的时机,如果紧靠进程自己去调用schedule函数完成调度,那么用户进程会一直执行下去,这样显然对其他进程是不公平的。调度程序需要注册一个定时器任务,它周期性的去检查当前运行的进程是否已经用尽时间片,如果已用尽那么会调用schedule函数调度其他进程占用CPU。

        下面看看如何通过java模拟:

        CPU:单例,用于模拟CPU,由一个线程驱动,默认时间片是5s。

        Task:模拟进程,被调度的实体。

        Job:进程中执行的任务,这个类是本模拟程序中抽象出来的,主要通过计数来模拟程序的运行。

        Scheduler:调度器,具有一个运行队列。schedule方法可以完成进程的调度。

        Timer:模拟定时器,用于完成定时任务,会周期性的调用Scheduler.schedule()检查当前运行的进程的时间片是否用尽,然后调度其他进程占用CPU。

        SleepSysCall:模拟慢系统调用,就是会导致进程阻塞的系统调用。具有一个等待队列。

        ReadFS:是SleepSysCall的一个实现,用于模拟读文件,会阻塞10s。

        CounterJob、CounterForkJob和SleepCallJob是Job的实现,模拟具体的任务,其中CounterForkJob会fork一个子进程,而SleepCallJob会调用阻塞的系统调用,就是用来模拟进程的阻塞和唤醒。

        下面看一下,程序的输出:

2012-8-28 16:29:10 com.chosen0ne.taskschedule.arch.CPU run
信息: CPU runs
2012-8-28 16:29:10 com.chosen0ne.taskschedule.arch.Timer run
信息: Scheduler ticks   //================// 定时器触发Scheduler
2012-8-28 16:29:10 com.chosen0ne.taskschedule.os.Task run
信息: Task JOB A switch in
2012-8-28 16:29:10 com.chosen0ne.taskschedule.job.CounterForkJob jobRun
信息: JOB A : 1
2012-8-28 16:29:11 com.chosen0ne.taskschedule.job.CounterForkJob jobRun
信息: JOB A : 2
2012-8-28 16:29:12 com.chosen0ne.taskschedule.job.CounterForkJob jobRun
信息: JOB A : 3
2012-8-28 16:29:13 com.chosen0ne.taskschedule.arch.Timer run
信息: Scheduler ticks
2012-8-28 16:29:13 com.chosen0ne.taskschedule.job.CounterForkJob jobRun
信息: JOB A : 4
2012-8-28 16:29:13 com.chosen0ne.taskschedule.os.Task fork
信息: fork task 'JOB C' //=============// 创建子进程
2012-8-28 16:29:14 com.chosen0ne.taskschedule.job.CounterForkJob jobRun
信息: JOB A : 5
2012-8-28 16:29:15 com.chosen0ne.taskschedule.job.CounterForkJob jobRun
信息: JOB A : 6
2012-8-28 16:29:16 com.chosen0ne.taskschedule.arch.Timer run
信息: Scheduler ticks
2012-8-28 16:29:16 com.chosen0ne.taskschedule.os.Scheduler schedule
信息: Task JOB B is selected to run, Task JOB A switch out //====// 上下文切换
2012-8-28 16:29:16 com.chosen0ne.taskschedule.os.Task run
信息: Task JOB B switch in
2012-8-28 16:29:16 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB B : 100
2012-8-28 16:29:17 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB B : 101
2012-8-28 16:29:18 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB B : 102
2012-8-28 16:29:19 com.chosen0ne.taskschedule.arch.Timer run
信息: Scheduler ticks
2012-8-28 16:29:19 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB B : 103
2012-8-28 16:29:20 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB B : 104
2012-8-28 16:29:21 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB B : 105
2012-8-28 16:29:22 com.chosen0ne.taskschedule.arch.Timer run
信息: Scheduler ticks
2012-8-28 16:29:22 com.chosen0ne.taskschedule.os.Scheduler schedule
信息: Task JOB D is selected to run, Task JOB B switch out
2012-8-28 16:29:22 com.chosen0ne.taskschedule.os.Task run
信息: Task JOB D switch in
2012-8-28 16:29:22 com.chosen0ne.taskschedule.job.SleepCallJob jobRun
信息: JOB D : 200
2012-8-28 16:29:23 com.chosen0ne.taskschedule.job.SleepCallJob jobRun
信息: JOB D : 201
2012-8-28 16:29:24 com.chosen0ne.taskschedule.job.SleepCallJob jobRun
信息: JOB D : 202
2012-8-28 16:29:25 com.chosen0ne.taskschedule.arch.Timer run
信息: Scheduler ticks
2012-8-28 16:29:25 com.chosen0ne.taskschedule.job.SleepCallJob jobRun
信息: JOB D : 203
2012-8-28 16:29:26 com.chosen0ne.taskschedule.job.SleepCallJob jobRun
信息: JOB D : 204
2012-8-28 16:29:26 com.chosen0ne.taskschedule.lib.SleepSysCall call
信息: JOB D sleeps  //===========================// 调用阻塞系统调用,进入阻塞状态
2012-8-28 16:29:27 com.chosen0ne.taskschedule.os.Task run
信息: Task JOB E switch in
2012-8-28 16:29:27 com.chosen0ne.taskschedule.job.SleepCallJob jobRun
信息: JOB E : 200
2012-8-28 16:29:28 com.chosen0ne.taskschedule.arch.Timer run
信息: Scheduler ticks
2012-8-28 16:29:28 com.chosen0ne.taskschedule.job.SleepCallJob jobRun
信息: JOB E : 201
2012-8-28 16:29:28 com.chosen0ne.taskschedule.lib.SleepSysCall call
信息: JOB E sleeps
2012-8-28 16:29:29 com.chosen0ne.taskschedule.os.Task run
信息: Task JOB C switch in
2012-8-28 16:29:29 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB C : 1000
2012-8-28 16:29:30 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB C : 1001
2012-8-28 16:29:31 com.chosen0ne.taskschedule.arch.Timer run
信息: Scheduler ticks
2012-8-28 16:29:31 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB C : 1002
2012-8-28 16:29:32 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB C : 1003
2012-8-28 16:29:33 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB C : 1004
2012-8-28 16:29:34 com.chosen0ne.taskschedule.arch.Timer run
信息: Scheduler ticks
2012-8-28 16:29:34 com.chosen0ne.taskschedule.os.Scheduler schedule
信息: Task JOB C is selected to run, Task JOB C switch out
2012-8-28 16:29:34 com.chosen0ne.taskschedule.os.Task run
信息: Task JOB C switch in
2012-8-28 16:29:34 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB C : 1005
2012-8-28 16:29:35 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB C : 1006
2012-8-28 16:29:36 com.chosen0ne.taskschedule.lib.ReadFS proc
信息: #### JOB D read data from FS  //==========// 从阻塞系统调用返回,进入可运行状态
2012-8-28 16:29:36 com.chosen0ne.taskschedule.lib.SleepSysCall$1 run
信息: JOB D wakes up
2012-8-28 16:29:36 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB C : 1007
2012-8-28 16:29:37 com.chosen0ne.taskschedule.arch.Timer run
信息: Scheduler ticks
2012-8-28 16:29:37 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB C : 1008
2012-8-28 16:29:38 com.chosen0ne.taskschedule.lib.ReadFS proc
信息: #### JOB E read data from FS
2012-8-28 16:29:38 com.chosen0ne.taskschedule.lib.SleepSysCall$1 run
信息: JOB E wakes up
2012-8-28 16:29:38 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB C : 1009
2012-8-28 16:29:39 com.chosen0ne.taskschedule.job.CounterJob jobRun
信息: JOB C : 1010

        源码见githup: https://github.com/chosen0ne/task-schedule-simulate


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值