进程调度函数schedule()分析

合集下载

schedule()函数

schedule()函数

schedule()函数schedule()函数是操作系统中的一个重要函数,用于调度进程,使之按照一定的顺序运行。

本文将对schedule()函数进行详细的介绍,包括其概念、功能、使用方法等方面。

在操作系统中,进程是计算机中最基本的执行单位。

每个进程都有自己的执行顺序,如何调度进程是操作系统的一个重要任务。

这时就需要用到schedule()函数,它能够将CPU资源分配给各个进程,并使它们按照一定的顺序执行。

schedule()函数的主要功能是将多个进程进行调度。

在切换到某个进程时,它需要执行相应的操作,包括保存当前进程的状态,然后加载要运行的进程的状态等等。

这样才能确保进程能够正常运行,保证系统的稳定性和高效性。

schedule()函数通常包含在操作系统的内核中,用户程序无法直接调用它。

通常,用户程序通过系统调用来向内核发出请求,然后由内核调用schedule()函数进行进程的调度。

在Linux系统中,schedule()函数是由内核进行管理的。

内核通过调用schedule()函数,按照某种算法来决定下一个要执行的进程。

这个算法通常是根据进程的优先级来进行调度。

当多个进程具有相同的优先级时,会采用一些其他的算法来进行调度,例如轮转法、多级反馈队列等等。

schedule()函数基本上是由内核驱动的。

当一个进程无法继续执行时,内核会启动调度程序,并从就绪队列中选择一个新的进程。

一旦一个新的进程被选中,内核会进行进程的切换,将当前进程的状态保存下来,然后加载要运行的进程的状态,并将控制权转移到新的进程中。

需要注意的是,schedule()函数的实现原理是高度依赖于具体的操作系统。

因此,在不同的操作系统中,schedule()函数的实现原理可能会有所不同。

五、总结。

python sched非阻塞用法

python sched非阻塞用法

python sched非阻塞用法Python的sched模块是一个通用的事件调度器。

它可以让你安排在未来的某个时间执行一个函数,或者定期执行一个函数。

默认情况下,sched是阻塞的,也就是说,当你调用sched.scheduler()方法时,它会阻塞当前的线程,直到有事件可以处理。

如果你想要使用一个非阻塞的调度器,你可以使用sched.scheduler的优先级功能。

下面是一个使用sched的非阻塞用法的例子:pythonimport schedimport times = sched.scheduler(time.time, time.sleep)def print_time(a='default'):print("From print_time", time.time(), a)def print_some_times():print(time.time())s.enter(10, 1, print_time)s.enter(5, 2, print_time, argument=('positional',))s.enter(5, 1, print_time, kwargs={'a': 'keyword'})s.run()print(time.time())print_some_times()在这个例子中,我们创建了一个非阻塞的调度器,然后安排了几个任务在未来的不同时间执行。

这些任务是打印当前的时间以及一些额外的信息。

然后我们调用s.run()来启动调度器。

这个方法会立即返回,不会阻塞当前的线程。

在调度器运行期间,它会按照优先级执行任务。

当所有的任务都执行完毕后,我们再次打印当前的时间。

linux sched_setscheduler函数解析

linux sched_setscheduler函数解析

linux sched_setscheduler函数解析sched_setscheduler函数是一个Linux系统调用函数,用于修改进程的调度策略和优先级。

函数原型为:```cint sched_setscheduler(pid_t pid, int policy, const structsched_param *param);```参数说明:- pid:要修改调度策略和优先级的进程ID。

如果pid为0,则表示修改当前进程。

- policy:要设置的调度策略。

可以取以下值:- SCHED_OTHER:普通进程调度策略,即默认策略。

这是一个非实时调度策略,由时间片轮转算法控制。

- SCHED_FIFO:先进先出调度策略。

使用FIFO调度策略的进程优先级比其他普通进程高。

- SCHED_RR:轮转调度策略。

与FIFO策略类似,但进程会在使用完时间片后轮转到等待队列的末尾。

- SCHED_BATCH:批处理调度策略。

适合批处理作业,将进程聚集在一起批量执行。

- SCHED_IDLE:空闲调度策略。

只有在没有其他优先级较高的进程运行时,才会执行该进程。

- SCHED_DEADLINE:截止时间调度策略。

用于实时系统,根据任务的截止时间进行调度。

- param:一个指向sched_param结构体的指针,用于设置进程的优先级和其他调度参数。

sched_param结构体包含一个int类型的成员sched_priority,表示进程的优先级。

函数返回值为0表示成功,返回-1表示失败并设置errno。

sched_setscheduler函数用于修改进程的调度策略和优先级。

在修改调度策略之前,需要获得相应的权限。

调用该函数后,进程会立即按照新的调度策略和优先级进行调度。

注意事项:- 一些调度策略(如SCHED_FIFO和SCHED_RR)需要root权限,因此需要以root用户身份运行程序或具有相应的权限。

- 修改调度策略和优先级可能会影响系统的整体性能和稳定性,需要谨慎使用。

进程调度算法总结

进程调度算法总结

进程调度算法总结所谓进程,简单来说是计算机中的各种任务,那么计算机如何分配系统资源以供这些任务使⽤呢?此篇博客⽬的就是为⼤家整理⼀下⼏种常见进程调度算法。

进度调度就是按照⼀定的策略,动态地把处理机分配给处于就绪队列的进程,使之执⾏。

常见的进程调度算法:1、先来先服务和短作业(进程)优先调度算法2、⾼优先权优先调度算法3、基于时间⽚的轮转调度算法下⾯细说:1、先来先服务和短作业优先调度算法1.1、先来先服务调度算法这种调度算法由字⾯意思理解很直观,所谓先来先服务,就是谁先来先服务谁。

结合进程,先来先服务调度算法就是对于优先到达就绪队列的进程采取优先服务的策略,直到该进程运⾏结束或发⽣某事件导致阻塞才放弃处理机。

这种调度算法是⼀种最简单的调度算法,适⽤于作业和进程。

当⽤于作业时,先进⼊后备队列的作业先运⾏。

1.2、短作业(进程)优先调度算法短作业(进程)优先调度算法,是对短作业或短进程进⾏得调度算法。

何为短?就是估计运⾏时间短。

该算法从后备队列或就绪队列选择估计运⾏时间较短的作业或进程,将他们调⼊内存运⾏,直到该进程运⾏结束或发⽣某事件导致阻塞才放弃处理机重新进⾏调度。

2、⾼优先权优先调度算法2.1、优先权调度算法上述所说的两种调度算法,过于简单,当系统中有紧急作业或进程,且不满⾜先进队列或运⾏时间短时,这些作业或进程将很难得到资源。

那么对于这些作业或进程,⼜该怎么办呢?因此,⼜有了优先权调度算法,所谓优先权调度算法,顾名思义就是谁的优先权⾼,谁就西安得到资源得以运⾏。

进⼀步将算法分为以下两种:2.1.1、⾮抢占式优先权算法在这种⽅式下,系统⼀旦把处理机分配给就绪队列中优先权最⾼的进程后,该进程便⼀直执⾏下去,直⾄完成;或因发⽣某事件使该进程放弃处理机时,系统⽅可再将处理机重新分配给另⼀优先权最⾼的进程。

这种调度算法主要⽤于批处理系统中;也可⽤于某些对实时性要求不严的实时系统中。

2.1.2、抢占式优先权算法在这种⽅式下,系统同样是把处理机分配给优先权最⾼的进程,使之执⾏。

linux核心函数

linux核心函数

linux核心函数Linux 内核是操作系统的核心部分,它提供了操作系统的核心功能,包括进程管理、内存管理、文件系统等。

Linux 内核的源代码中包含了大量的函数,用于实现各种操作系统的功能。

以下是一些Linux 内核中常见的核心函数,它们扮演着关键的角色:1.进程管理函数:–fork():创建一个新的进程。

–exec():在当前进程中执行一个新的程序。

–wait():等待子进程结束。

–exit():终止当前进程。

2.调度和任务管理函数:–schedule():进行进程调度。

–yield():主动让出CPU,将当前进程移动到就绪队列的末尾。

–wake_up_process():唤醒一个等待中的进程。

3.内存管理函数:–kmalloc():在内核中分配内存。

–kfree():释放内核中的内存。

–vmalloc():在虚拟地址空间中分配内存。

4.文件系统函数:–open():打开一个文件。

–read():从文件中读取数据。

–write():向文件中写入数据。

–close():关闭文件。

5.设备驱动函数:–register_chrdev():注册字符设备。

–unregister_chrdev():注销字符设备。

–request_irq():注册中断处理函数。

6.网络函数:–socket():创建套接字。

–bind():将套接字与地址绑定。

–listen():侦听传入连接请求。

–accept():接受传入的连接请求。

7.定时器和时钟函数:–timer_create():创建一个定时器。

–timer_settime():设置定时器的时间。

–gettimeofday():获取当前时间。

8.同步和互斥函数:–spin_lock():获取自旋锁。

–spin_unlock():释放自旋锁。

–mutex_lock():获取互斥锁。

–mutex_unlock():释放互斥锁。

这些函数仅仅是Linux 内核中众多函数的一小部分,Linux 内核的源代码非常庞大而复杂,包含了各种各样的功能和模块。

schedule库的用法 -回复

schedule库的用法 -回复

schedule库的用法-回复"Schedule" 库的用法在软件开发和计算机科学中,调度(scheduling)是一个重要的概念。

调度是指为一系列的任务或事件分配合适的时间和先后顺序的过程。

在各种编程语言和框架中,都有为了处理程序中的任务调度而设计的库和工具。

其中一个常用的调度库是Python 中的"schedule"。

"schedule" 是一个简单且易于使用的Python 库,它提供了一种便捷的方式来安排和管理程序中的任务。

通过使用"schedule",开发人员可以轻松创建和管理任务的调度,使得程序的执行具有更高的灵活性和可控性。

下面将介绍"schedule" 库的用法,包括其安装、基本用法和一些高级功能。

1. 安装"schedule" 库要使用"schedule" 库,首先需要在Python 环境中安装它。

可以使用pip 包管理器进行安装,命令如下:pythonpip install schedule安装完成后,就可以在Python 脚本中导入"schedule" 模块并开始使用它了。

2. 基本用法"schedule" 库的基本用法非常简单。

下面是一个使用"schedule" 调度一个简单任务的示例代码:pythonimport scheduleimport timedef job():print("This is a scheduled job.")# 创建一个任务,每隔一分钟执行一次job 函数schedule.every(1).minutes.do(job)# 循环执行调度的任务while True:schedule.run_pending()time.sleep(1)在上面的例子中,我们首先导入了"schedule" 和"time" 模块。

操作系统五种进程调度算法的代码

操作系统五种进程调度算法的代码

操作系统五种进程调度算法的代码一、先来先服务(FCFS)调度算法先来先服务(FCFS)调度算法是操作系统处理进程调度时比较常用的算法,它的基本思想是按照进程的提交时间的先后顺序依次调度进程,新提交的进程会在当前运行进程之后排队,下面通过C语言代码来实现先来先服务(FCFS)调度算法:#include <stdio.h>#include <stdlib.h>//定义进程的数据结构struct Processint pid; // 进程标识符int at; // 到达时间int bt; // 执行时间};//进程调度函数void fcfs_schedule(struct Process *processes, int n)int i, j;//根据进程的到达时间排序for(i = 0; i < n; i++)for(j = i+1; j < n; j++)if(processes[i].at > processes[j].at) struct Process temp = processes[i]; processes[i] = processes[j];processes[j] = temp;//获取各个进程执行完毕的时间int ct[n];ct[0] = processes[0].at + processes[0].bt; for(i = 1; i < n; i++)if(ct[i-1] > processes[i].at)ct[i] = ct[i-1] + processes[i].bt;elsect[i] = processes[i].at + processes[i].bt; //计算各个进程的周转时间和带权周转时间int tat[n], wt[n], wt_r[n];for(i = 0; i < n; i++)tat[i] = ct[i] - processes[i].at;wt[i] = tat[i] - processes[i].bt;wt_r[i] = wt[i] / processes[i].bt;printf("P%d:\tAT=%d\tBT=%d\tCT=%d\tTAT=%d\tWT=%d\tWT_R=%f\n", processes[i].pid, processes[i].at, processes[i].bt, ct[i], tat[i], wt[i], wt_r[i]);//主函数int mainstruct Process processes[] ={1,0,3},{2,3,5},{3,4,6},{4,5,2},{5,6,4}};fcfs_schedule(processes, 5);return 0;输出:。

schedule函数主要流程

schedule函数主要流程

上层调度,linux调度的核心函数为schedule,schedule函数封装了内核调度的框架。

细节实现上调用具体的调度类中的函数实现。

schedule函数主要流程为:1,将当前进程从相应的运行队列中删除;2,计算和更新调度实体和进程的相关调度信息;3,将当前进程重新插入到调度运行队列中,对于CFS调度,根据具体的运行时间进行插入而对于实时调度插入到对应优先级队列的队尾;4,从运行队列中选择运行的下一个进程;5,进程调度信息和上下文切换;当进程上下文切换后,调度就基本上完成了,当前运行的进程就是切换过来的进程了。

[cpp] view plaincopyprint?1. /*内核和其他部分用于调用进程调度器的入口,选择2. 哪个进程可以运行,何时将其投入运行。

schedule通常3. 都需要和一个具体的调度类相关联,也就是说,他4. 会找到一个最高优先级的调度类,后者需要有自己的5. 可运行队列,然后问后者谁才是下一个该运行的进程6. 该函数唯一重要的事情是,他回调用pick_next_task*/7. asmlinkage void __sched schedule(void)8. {9. struct task_struct *prev, *next;10. unsigned long *switch_count;11. struct rq *rq;12. int cpu;13.14. need_resched:15. preempt_disable();16. cpu = smp_processor_id();17. rq = cpu_rq(cpu);/*得到特定cpu的rq*/18. rcu_sched_qs(cpu);19. prev = rq->curr;/*当前的运行进程*/20. switch_count = &prev->nivcsw;/*进程切换计数*/21.22. release_kernel_lock(prev);23. need_resched_nonpreemptible:24.25. schedule_debug(prev);26.27. if (sched_feat(HRTICK))28. hrtick_clear(rq);29.30. spin_lock_irq(&rq->lock);31. update_rq_clock(rq);/*更新rq的clock属性*/32. clear_tsk_need_resched(prev);/*清楚prev进程的调度位*/33.34. if (prev->state && !(preempt_count()& PREEMPT_ACTIVE)){35. if (unlikely(signal_pending_state(prev->state, prev)))36. prev->state = TASK_RUNNING;37. else/*从运行队列中删除prev进程,根据调度类的38. 不同,实现不同*/39. deactivate_task(rq, prev, 1);40. switch_count = &prev->nvcsw;41. }42. /*现只对实时进程有用*/43. pre_schedule(rq, prev);44.45. if (unlikely(!rq->nr_running))46. idle_balance(cpu, rq);47. /*将当前进程,也就是被切换出去的进程重新48. 插入到各自的运行队列中,对于CFS算法插入49. 到合适的位置上,对于实时调度插入到同一个50. 优先级队列的链表尾部*/51. put_prev_task(rq, prev);52. /*从各自的运行队列中选择下一个进程来运行*/53. next = pick_next_task(rq);54.55. if (likely(prev != next)){56. /*更新切换出去和进来进程以及对应rq的相关变量*/57. sched_info_switch(prev, next);58. perf_event_task_sched_out(prev, next, cpu);59.60. rq->nr_switches++;/*切换记录*/61. rq->curr = next;62. ++*switch_count;63. /*上下文切换,在进程切换已经介绍*/64. context_switch(rq, prev, next);/* unlocks the rq */65. /*66. * the context switch might have flipped the stack from under67. * us, hence refresh the local variables.68. */69. cpu = smp_processor_id();70. rq = cpu_rq(cpu);71. } else72. spin_unlock_irq(&rq->lock);73. /*对于实时进程有用到*/74. post_schedule(rq);75.76. if (unlikely(reacquire_kernel_lock(current)< 0))77. goto need_resched_nonpreemptible;78.79. preempt_enable_no_resched();80. if (need_resched())81. goto need_resched;82. }对于cpu_rq函数[cpp] view plaincopyprint?1. /*通过向上加偏移的方式得到rq,这里可以看出2. runqueues为一个rq结构的数组,cpu为数组下标*/3. #define cpu_rq(cpu)(&per_cpu(runqueues, (cpu)))deactivate_task函数实现[cpp] view plaincopyprint?1. /*2. * deactivate_task - remove a task from the runqueue.3. */4. static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep)5. {6. if (task_contributes_to_load(p))7. rq->nr_uninterruptible++;8. /*具体操作*/9. dequeue_task(rq, p, sleep);10. dec_nr_running(rq);/*rq中当前进程的运行数减一*/11. }我们看具体的操作1. static void dequeue_task(struct rq *rq, struct task_struct *p, int sleep)2. {3. if (sleep){/*如果sleep不为0,更新se中相关变量*/4. if (p->st_wakeup){5. update_avg(&p->se.avg_overlap,6. p->se.sum_exec_runtime - p->st_wakeup);7. p->st_wakeup = 0;8. } else {9. update_avg(&p->se.avg_wakeup,10. sysctl_sched_wakeup_granularity);11. }12. }13. /*更新进程的sched_info数据结构中相关属性*/14. sched_info_dequeued(p);15. /*调用具体调度类的函数从他的运行队列中删除*/16. p->sched_class->dequeue_task(rq, p, sleep);17. p->se.on_rq = 0;18. }可见,调用了具体运行队列的删除函数,我们看最关键的选择下一个进程的方式。

schedule的用法和搭配java

schedule的用法和搭配java

schedule的用法和搭配java “schedule”的用法和搭配。

文章应该包括以下内容:1. 什么是“schedule”?2. “schedule”的基本用法。

3. “schedule”的常见搭配。

4. Java中如何使用“schedule”?5. “schedule”在实际应用中的案例。

6. 使用“schedule”可能存在的问题和解决方法。

1. 什么是“schedule”?“schedule”一词可以解释为“安排,计划”,是指按照一定的时间表规划和调度任务的过程。

它广泛应用于生活和工作中,可以帮助人们组织时间,提高效率。

在计算机编程中,“schedule”一词通常指计划任务执行的时间和频率,以及执行时所需的资源和条件。

2. “schedule”的基本用法“schedule”的基本用法包括三个方面:任务,执行时间和执行频率。

任务是指要执行的功能或动作,这可以是函数、方法、脚本或其他可执行的程序。

执行时间是指任务要在何时开始执行,通常是一个具体的日期和时间。

执行频率是指任务要执行的频率,即是只执行一次还是按照一定的频率重复执行。

例如,如果要在每天早上6点执行一个任务,则需要指定任务内容、执行时间和执行频率。

可以使用现有的任务安排工具(如计划任务)来实现这一功能,或者通过编程手动调度。

3. “schedule”的常见搭配“schedule”常见的搭配包括以下几种:- Cron表达式:Cron表达式是一种通用的任务调度表达式,用于指定任务执行的时间和频率。

它通常由五个或六个字段组成,用空格或星号分隔。

例如,“0 0 6 * * ?”表示每天早上6点执行任务。

- Quartz调度器:Quartz是一种常用的任务调度器,用于在Java应用程序中安排任务执行。

它支持Cron表达式和其他常见的调度表达式,并提供了许多灵活性和扩展性选项。

- Timer类:Timer是Java.util包中的一个类,用于在Java应用程序中实现定时任务。

计算机操作系统实验---进程调度

计算机操作系统实验---进程调度

操作系统实验报告--进程调度计科02-8 王长青05年4月17日计算机操作系统实验——进程调度一.实验目的进程调度是处理机管理的核心内容。

通过本实验可以加深理解有关进程控制块、进程队列的概念,并体会和了解优先数调度算法的具体实施办法。

二.程序功能本程序使用VC++编译调试,用于实现进程优先数调度的模拟。

主要包含三个模块:1、主界面:用于显示进程调度的过程。

2、数据录入模块:用于获取进程的初始值,其中有三种获取方式,手动输入方式、随即生成方式和从文件中读去数据的方式。

当用户在主窗口中点击“开始”菜单项时即可打开数据录入对话框,用户通过这三种方式之一均可完成数据的录入。

3、进程控制模块:主要实现创建新的进程,就绪队列的管理,完成队列的管理,进程的调度。

三.实验原理(1)本程序采用优先数调度算法对进程进行调度,每个进程可有三个状态,即:就绪状态,运行状态,完成状态。

并假设初始状态为就绪状态。

这三种状态的转换情况如右图:(2)为了便于处理,程序中的某进程运行时间以时间片为单位计算。

各进程的优先数以及进程需运行的时间片数的初始值均由用户给定(通过数据录入模块完成)。

(3)程序通过设置一个定时器来实现时间片的轮转,时间片的大小是1秒,在定时器消息的响应函数中从用户录入的数据中读取一个创建进程,将其加入到就绪队列中,然后进行调度和执行。

在调度函数中,对于遇到优先数一致的情况,采用FIFO策略解决。

(4)在优先数算法中,进程每执行一次,优先数减3,进程还需要运行的时间数减1。

四.详细设计(1)设计进程控制块PCB结构:struct PCB{ int pid; //进程号int pri; //进程优先数int time; //进程所需运行时间int status; // 进程状态 0就绪,1 执行,-1完成};(2)将进程的各种操作封装在类CProMoni中,该类的定义如下:class CProMoni{public:CProMoni();virtual ~CProMoni();void InsertRQ(PCB* p); //将p所指的进程插入到就绪队列中void InsertFQ(PCB* p); //将p所指的进程插入到完成队列中void ProSchedule(); //进程调度函数void ProRun(); //运行函数void Display(CDC* pDC); //以表格形式输出运行过程bool GetFinishFlag();bool OpenLogFile(); //打开日志文件void CloseLogFile(); //关闭日志文件bool WriteLogToFile(); //向日志文件中写入数据private:PCB *m_pRunning; //指向当前运行的进程CPtrList m_readyList; //就绪队列CPtrList m_finishList; //完成队列bool m_finish; //完成标志CString m_LogFileName; //日志文件名CStdioFile m_LogFile; //日志文件public:int m_clock; //时钟序列};(3)主要成员函数的实现:void CProMoni::InsertRQ(PCB* p){ //将p插入到就绪队列中POSITION pre,pos=m_readyList.GetHeadPosition();PCB *q;while(pos!=NULL){pre=pos;q=(PCB*)m_readyList.GetNext(pos);if(q->pri < p->pri){m_readyList.InsertBefore(pre,p);return;}}if(pos==NULL){m_readyList.AddTail(p);}}void CProMoni::ProSchedule(){//进程调度PCB *p;if(m_pRunning==NULL){if(m_readyList.IsEmpty()){m_finish=true;return;}else{p=(PCB*)m_readyList.RemoveHead();m_pRunning=p;}}else{if(!m_readyList.IsEmpty()){p=(PCB*)m_readyList.GetHead();//m_readyList将头节点与当前PCB的权值比较if(p->pri > m_pRunning->pri ){PCB *q=m_pRunning;m_pRunning=(PCB*)m_readyList.RemoveHead();m_pRunning->status=1;q->status=0;InsertRQ(q);}}}}void CProMoni::ProRun(){//运行进程if(!m_finish){if(m_pRunning==NULL){ AfxMessageBox("当前运行的进程不存在!");return;}m_pRunning->pri-=3;m_pRunning->time-=1;{ m_pRunning->time=0;PCB*p=m_pRunning;p->status=-1;InsertFQ(p);m_pRunning=NULL;}}}(4)试图类的主要成员函数:PCB* CProcessView::CreatePCB(){//创建PCBPCB* p=new PCB;p->pid=n+1;p->pri=m_pris[n];p->time=m_times[n];p->status=0;n++;return p;}#include"pritimedlg.h"void CProcessView::OnStart(){ CPriTimeDlg dlg; //定义数据录入对话框dlg.DoModal();if(dlg.m_ok){ m_proTotal=dlg.m_proNum;for(int i=0;i<m_proTotal;i++){ m_pris[i]=dlg.m_pris[i];m_times[i]=dlg.m_times[i];}m_proMoni.OpenLogFile(); //打开日志文件PCB* p=CreatePCB(); //创建新进程m_proMoni.InsertRQ(p); //将新进程插入到就绪队列中m_proMoni.WriteLogToFile(); //写日志文件m_proMoni.ProSchedule(); //进程调度m_start=true; //设置开始标志Invalidate(); //刷新视图m_killTimer=false;SetTimer(1,1000,NULL);//设置定时器}}void CProcessView::OnTimer(UINT nIDEvent){ m_proMoni.m_clock++;m_proMoni.WriteLogToFile();//写日志m_proMoni.ProRun(); //运行进程if(n<m_proTotal){ PCB *p=CreatePCB();//创建新进程m_proMoni.InsertRQ(p);}m_proMoni.ProSchedule();Invalidate();if(m_proMoni.GetFinishFlag()){//若已完成则删除定时器KillTimer(1);m_killTimer=true;AfxMessageBox("演示完毕");}CScrollView::OnTimer(nIDEvent);}五.运行结果(1)数据录入界面:(2)进程调度过程的结果:六、实验总结通过本实验使我对进程的相关概念及进程的优先数调度算法有了更深的理解,使自己在程序设计及编制方面也有了一定的提高。

schedule函数主要流程

schedule函数主要流程

上层调度,linux调度的核心函数为schedule,schedule函数封装了内核调度的框架。

细节实现上调用具体的调度类中的函数实现。

schedule函数主要流程为:1,将当前进程从相应的运行队列中删除;2,计算和更新调度实体和进程的相关调度信息;3,将当前进程重新插入到调度运行队列中,对于CFS调度,根据具体的运行时间进行插入而对于实时调度插入到对应优先级队列的队尾;4,从运行队列中选择运行的下一个进程;5,进程调度信息和上下文切换;当进程上下文切换后,调度就基本上完成了,当前运行的进程就是切换过来的进程了。

[cpp] view plaincopyprint?1. /*内核和其他部分用于调用进程调度器的入口,选择2. 哪个进程可以运行,何时将其投入运行。

schedule通常3. 都需要和一个具体的调度类相关联,也就是说,他4. 会找到一个最高优先级的调度类,后者需要有自己的5. 可运行队列,然后问后者谁才是下一个该运行的进程6. 该函数唯一重要的事情是,他回调用pick_next_task*/7. asmlinkage void __sched schedule(void)8. {9. struct task_struct *prev, *next;10. unsigned long *switch_count;11. struct rq *rq;12. int cpu;13.14. need_resched:15. preempt_disable();16. cpu = smp_processor_id();17. rq = cpu_rq(cpu);/*得到特定cpu的rq*/18. rcu_sched_qs(cpu);19. prev = rq->curr;/*当前的运行进程*/20. switch_count = &prev->nivcsw;/*进程切换计数*/21.22. release_kernel_lock(prev);23. need_resched_nonpreemptible:24.25. schedule_debug(prev);26.27. if (sched_feat(HRTICK))28. hrtick_clear(rq);29.30. spin_lock_irq(&rq->lock);31. update_rq_clock(rq);/*更新rq的clock属性*/32. clear_tsk_need_resched(prev);/*清楚prev进程的调度位*/33.34. if (prev->state && !(preempt_count()& PREEMPT_ACTIVE)){35. if (unlikely(signal_pending_state(prev->state, prev)))36. prev->state = TASK_RUNNING;37. else/*从运行队列中删除prev进程,根据调度类的38. 不同,实现不同*/39. deactivate_task(rq, prev, 1);40. switch_count = &prev->nvcsw;41. }42. /*现只对实时进程有用*/43. pre_schedule(rq, prev);44.45. if (unlikely(!rq->nr_running))46. idle_balance(cpu, rq);47. /*将当前进程,也就是被切换出去的进程重新48. 插入到各自的运行队列中,对于CFS算法插入49. 到合适的位置上,对于实时调度插入到同一个50. 优先级队列的链表尾部*/51. put_prev_task(rq, prev);52. /*从各自的运行队列中选择下一个进程来运行*/53. next = pick_next_task(rq);54.55. if (likely(prev != next)){56. /*更新切换出去和进来进程以及对应rq的相关变量*/57. sched_info_switch(prev, next);58. perf_event_task_sched_out(prev, next, cpu);59.60. rq->nr_switches++;/*切换记录*/61. rq->curr = next;62. ++*switch_count;63. /*上下文切换,在进程切换已经介绍*/64. context_switch(rq, prev, next);/* unlocks the rq */65. /*66. * the context switch might have flipped the stack from under67. * us, hence refresh the local variables.68. */69. cpu = smp_processor_id();70. rq = cpu_rq(cpu);71. } else72. spin_unlock_irq(&rq->lock);73. /*对于实时进程有用到*/74. post_schedule(rq);75.76. if (unlikely(reacquire_kernel_lock(current)< 0))77. goto need_resched_nonpreemptible;78.79. preempt_enable_no_resched();80. if (need_resched())81. goto need_resched;82. }对于cpu_rq函数[cpp] view plaincopyprint?1. /*通过向上加偏移的方式得到rq,这里可以看出2. runqueues为一个rq结构的数组,cpu为数组下标*/3. #define cpu_rq(cpu)(&per_cpu(runqueues, (cpu)))deactivate_task函数实现[cpp] view plaincopyprint?1. /*2. * deactivate_task - remove a task from the runqueue.3. */4. static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep)5. {6. if (task_contributes_to_load(p))7. rq->nr_uninterruptible++;8. /*具体操作*/9. dequeue_task(rq, p, sleep);10. dec_nr_running(rq);/*rq中当前进程的运行数减一*/11. }我们看具体的操作1. static void dequeue_task(struct rq *rq, struct task_struct *p, int sleep)2. {3. if (sleep){/*如果sleep不为0,更新se中相关变量*/4. if (p->st_wakeup){5. update_avg(&p->se.avg_overlap,6. p->se.sum_exec_runtime - p->st_wakeup);7. p->st_wakeup = 0;8. } else {9. update_avg(&p->se.avg_wakeup,10. sysctl_sched_wakeup_granularity);11. }12. }13. /*更新进程的sched_info数据结构中相关属性*/14. sched_info_dequeued(p);15. /*调用具体调度类的函数从他的运行队列中删除*/16. p->sched_class->dequeue_task(rq, p, sleep);17. p->se.on_rq = 0;18. }可见,调用了具体运行队列的删除函数,我们看最关键的选择下一个进程的方式。

Oracle数据库的SCHEDULE(调度程序)

Oracle数据库的SCHEDULE(调度程序)

Oracle数据库的SCHEDULE(调度程序)很多情况下,数据库管理员或用户需要自动调度和运行很多类型的作业,例如,执行维护工作(如数据库备份);数据加载和验证例程;生成报表;收集优化程序统计信息或执行业务流程。

可以使用调度程序功能指定任务在将来某个时间点运行。

作业可以在数据库中、在驻留数据库实例的机器上甚至在远程机器上运行。

可以结合使用调度程序和Resource Manager(资源管理器)。

调度程序可以激活Resource Manager计划,并按照为各种Resource Manager使用者组指定的优先级来运行作业。

调度程序是在Oracle 10g版本中引入的,在11g版本中得到了大大增强。

较早的数据库版本通过DBMS_JOB功能提供作业调度功能。

为了达达到向后兼容的目的,当前版本依然支持此功能,但它的功能多样性远不及调度程度。

1、调度程序体系结构数据字典包含一个作为所有调度程序作业的存储点的表。

可以通过DBA_SCHEDULER_JOBS视图查询此表。

作业队列协调器后台进程CJQ0监视此表,根据需要启动作业队列进程Jnnn来运行作业。

如果在任何定义的、活动的调度程序作业,就自动启动CJBQ0进程。

根据需要启动Jnnn进程,但是最大数量受JOB_QUEUE_PROCESSES实例参数限制,该参数可以是0-1000(默认值)的任何值。

如果将值设为0,那么将不会运行调程。

作业队列协调器从作业队列表中选取作业,将它们传递给作业队列进程执行。

它还根据需要启动和终止作业队列进程。

要查看当前正在运行的进程,可查询V$PROCESS视图。

select program from v$process where program like '%J%';定义为过程的作业在数据库中运行。

作业也可以定义为操作系统命令或shell脚本:这些将作为外部操作系统任务运行。

作业的触发因素可以是时间或事件。

进程的调度算法

进程的调度算法

进程的调度算法调度算法的实质是:根据系统的资源分配策略所规定的资源分配算法。

先介绍⼀下进程调度与作业调度的区别:进程调度是真正让某个就绪状态的进程到处理机上运⾏,⽽作业调度只是使作业具有了竞争处理机的机会。

进程调度(⼜称微观调度、低级调度、短程调度):是按照某种调度算法从就绪状态的进程中选择⼀个进程到处理机上运⾏。

负责进程调度功能的内核程序称为进程调度程序。

作业调度(⼜称⾼级调度、宏观调度、长程调度):是按某种调度算法从后备作业队列中选择作业装⼊内存运⾏;另外当该作业执⾏完毕后,还负责回收系统资源。

完成作业调度功能的程序称为作业调度程序。

下⾯介绍⼏种常见的调度算法:先来先服务(FCFS,first come first served)FCFS调度算法是⼀种最简单的调度算法,该调度算法既可以⽤于作业调度也可以⽤于进程调度。

在作业调度中,算法每次从后备作业队列中选择最先进⼊该队列的⼀个或⼏个作业,将它们调⼊内存,分配必要的资源,创建进程并放⼊就绪队列。

在进程调度中,FCFS调度算法每次从就绪队列中选择最先进⼊该队列的进程,将处理机分配给它,使之投⼊运⾏,直到完成或因某种原因⽽阻塞时才释放处理机。

优点:保证了公平性,规则简单缺点:有利于长进程⽽不利于短进程,有利于CPU 繁忙的进程,⽽不利于I/O 繁忙的进程短作业优先(SJF,Shortest Job First)短作业(进程)优先调度算法是指对短作业(进程)优先调度的算法。

短作业优先(SJF)调度算法是从后备队列中选择⼀个或若⼲个估计运⾏时间最短的作业,将它们调⼊内存运⾏。

⽽短进程优先(SPF)调度算法,则是从就绪队列中选择⼀个估计运⾏时间最短的进程,将处理机分配给它,使之⽴即执⾏,直到完成或发⽣某事件⽽阻塞时,才释放处理机。

优点:相⽐FCFS 算法,该算法可改善平均周转时间和平均带权周转时间,缩短进程的等待时间,提⾼系统的吞吐量。

缺点:该算法对长作业不利,SJF调度算法中长作业的周转时间会增加。

schedule用法

schedule用法

了解和使用schedule
简介
在日常工作和生活中,时间管理是一个非常重要的方面。

我们常常需要计划和
安排时间来完成任务,参加会议,约定活动等。

为了更好地管理时间和提高工作效率,我们可以借助一些工具。

其中一个值得推荐的工具是schedule。

什么是schedule
schedule是一个Python第三方库,用于在特定时间执行定时任务或定期计划。

它可以帮助我们安排任务,提醒任务和自动化一些重复性的工作。

schedule库非
常易于使用,具有强大的功能和灵活的调度选项。

安装schedule
要开始使用schedule,首先我们需要在Python环境中安装它。

可以通过以下
命令来安装schedule库:
pip install schedule
基本用法
创建一个简单的定时任务
现在,让我们看一下如何使用schedule来创建一个简单的定时任务。

假设我
们想每隔一分钟打印一次。

进程调度实验报告源码

进程调度实验报告源码

一、实验目的本次实验旨在通过模拟进程调度过程,加深对进程调度算法的理解,并掌握进程调度程序的设计与实现方法。

实验内容主要包括:创建进程、进程调度、进程执行、进程结束等。

二、实验环境操作系统:Linux编程语言:C/C++三、实验内容1. 进程调度算法本实验采用三种进程调度算法:FIFO(先进先出)、时间片轮转法、多级反馈队列调度算法。

2. 进程调度程序设计进程调度程序主要由以下部分组成:(1)进程控制块(PCB)PCB用于描述进程的基本信息,包括进程名、到达时间、需要运行时间、已运行时间、进程状态等。

(2)就绪队列就绪队列用于存储处于就绪状态的进程,按照进程的优先级或到达时间进行排序。

(3)进程调度函数进程调度函数负责从就绪队列中选择一个进程进行执行,并将CPU分配给该进程。

(4)进程执行函数进程执行函数负责模拟进程的执行过程,包括进程的创建、执行、结束等。

四、实验源码```c#include <stdio.h>#include <stdlib.h>#include <time.h>#define MAX_PROCESSES 10typedef struct PCB {int pid;int arrival_time;int need_time;int used_time;int priority;int state; // 0: 等待 1: 运行 2: 完成} PCB;PCB processes[MAX_PROCESSES];int process_count = 0;typedef struct Queue {PCB queue;int front;int rear;int size;} Queue;Queue ready_queue;void init_queue(Queue q) {q->queue = (PCB )malloc(sizeof(PCB) MAX_PROCESSES); q->front = q->rear = 0;q->size = 0;}void enqueue(Queue q, PCB p) {if (q->size == MAX_PROCESSES) {printf("Queue is full.\n");return;}q->queue[q->rear] = p;q->rear = (q->rear + 1) % MAX_PROCESSES; q->size++;}PCB dequeue(Queue q) {if (q->size == 0) {printf("Queue is empty.\n");return NULL;}PCB p = &q->queue[q->front];q->front = (q->front + 1) % MAX_PROCESSES; q->size--;return p;}int is_empty(Queue q) {return q->size == 0;}void print_queue(Queue q) {printf("Queue: ");for (int i = 0; i < q->size; i++) {PCB p = &q->queue[(q->front + i) % MAX_PROCESSES];printf("PID: %d, Arrival Time: %d, Need Time: %d, Used Time: %d, Priority: %d, State: %d\n",p->pid, p->arrival_time, p->need_time, p->used_time, p->priority, p->state);}}void init_processes() {for (int i = 0; i < MAX_PROCESSES; i++) {processes[i].pid = i;processes[i].arrival_time = rand() % 10;processes[i].need_time = rand() % 10 + 1;processes[i].used_time = 0;processes[i].priority = rand() % 3;processes[i].state = 0;}}void schedule() {int time = 0;while (process_count > 0) {for (int i = 0; i < process_count; i++) {PCB p = &processes[i];if (p->arrival_time == time) {enqueue(&ready_queue, p);p->state = 1;}}if (!is_empty(&ready_queue)) {PCB p = dequeue(&ready_queue);p->used_time++;printf("Process %d is running.\n", p->pid);if (p->used_time == p->need_time) {p->state = 2;printf("Process %d is finished.\n", p->pid); }}time++;}}int main() {srand(time(NULL));init_queue(&ready_queue);init_processes();process_count = rand() % MAX_PROCESSES + 1;schedule();print_queue(&ready_queue);return 0;}```五、实验结果与分析1. FIFO调度算法实验结果表明,FIFO调度算法按照进程的到达时间进行调度,可能导致短作业等待时间长,效率较低。

schedule库的用法

schedule库的用法

schedule库的用法【最新版】目录1.schedule 库的概述2.schedule 库的主要功能3.schedule 库的使用方法4.schedule 库的优点与局限性5.总结正文1.schedule 库的概述schedule 库是一个 Python 中的时间调度库,它可以让用户在特定的时间执行特定的任务。

schedule 库提供了定时任务的创建、调度和管理功能,使得用户可以方便地实现复杂的时间相关的任务。

2.schedule 库的主要功能schedule 库的主要功能有:- 定时任务的创建:用户可以创建一个定时任务,指定任务的执行时间、执行间隔以及要执行的函数。

- 定时任务的调度:schedule 库可以根据用户创建的任务,自动进行任务的调度,确保任务在指定的时间执行。

- 定时任务的管理:schedule 库提供了任务的添加、删除、修改等管理功能,方便用户对任务进行管理。

3.schedule 库的使用方法以下是一个 schedule 库的简单示例:```pythonimport scheduleimport timedef job():print("任务执行,当前时间:", time.time())# 创建一个定时任务,每隔 5 秒执行一次 job 函数schedule.every(5).seconds.do(job)# 启动 schedule 库的定时任务调度while True:schedule.run_pending()time.sleep(1)```4.schedule 库的优点与局限性schedule 库的优点:- 方便:schedule 库提供了简单的 API,用户可以轻松地创建、调度和管理定时任务。

- 可靠:schedule 库可以确保定时任务在指定的时间执行,不受程序执行过程的影响。

schedule 库的局限性:- 任务数量限制:schedule 库在单个进程中可管理的任务数量有限,当任务数量较多时,可能会影响程序的性能。

python中的schedule函数

python中的schedule函数

python中的schedule函数schedule函数是一个在Python中用于以一定顺序执行任务的库。

它使用起来非常方便,能够帮助我们非常容易地实现按固定时间间隔或者固定时间点执行任务的功能。

schedule提供两种基本的任务执行方式:有延时的执行和循环执行。

有延时的执行可以让我们在一定间隔内执行一段代码,而循环执行则可以让我们在任意时间点重复执行一段代码。

schedule还提供了一些高级功能,如调度布尔值和定时器。

在这些方面,schedule具有广泛的适用性和灵活性。

首先,我们来看看如何使用schedule进行需要延时执行的任务。

在schedule中实现定时任务的方法非常好,只需要为需要定时调度的函数添加一个装饰器@schedule.interval_seconds() ,并设置任务执行的时间间隔即可:```import scheduleimport timedef job():print("I'm working...")schedule.every(10).seconds.do(job)while True:schedule.run_pending()time.sleep(1)```这里我们需要定义一个函数job(),用于在每个10秒间隔内被执行一次,接着让schedule去执行它。

在代码中指定了需要每10秒被调度执行一次,而time.sleep(1)则让程序每隔1秒检查schedule对象中定时任务是否需要运行。

值得一提的是,这种方式支持的时间单位非常多,并且可以同时使用多个时间单位。

例如,我们可以结合小时和分钟来设定任务执行的时间:这是一个每小时0分相应任务的例子。

schedule库会在每个小时的0分时调度这个任务并执行。

对于需要做循环执行任务的情况,我们需要使用@schedul.interval()或者@scheduler.every()来设置我们想要的循环时间:这段代码中,我们设定了每天的10:30执行一次事先定义的job()函数。

process schedule调用原理

process schedule调用原理

process schedule调用原理
Process Schedule(进程调度)是操作系统中的一个功能模块,它通过对所有进程的优先级和状态的评估,为每个进程分配CPU时间片,从而控制进程在CPU上的运行顺序和时长。

其调度原理通常分为几个步骤:
1. 评估进程的优先级:通过进程的属性如优先级、CPU时间占用、等待时间等来评估每个进程的优先级。

2. 选择被调度的进程:根据各个进程的优先级和当前CPU资源的使用情况,调度算法会决定哪个进程会被选中来占用CPU资源。

3. 分配CPU时间片:经过选择后,系统会为被调度的进程分配一个时间片,时间片的长短通常通过任务的优先级和进程的属性来确定。

4. 运行进程:被选中的进程开始占用CPU资源并运行,直到它的时间片用完或者进程主动释放CPU,进程管理模块会再次进行调度,选中下一个进程占用CPU。

5. 进程状态更新:当一个进程不再执行时,它的状态将被更新为等待状态或者终止状态。

所有进程的状态会不断更新,以保证系统高效稳定地运行。

这些步骤是进程调度的基本过程,不同的操作系统会根据不同的需求和场景选择不同的调度算法,如先来先服务(FIFO)、最短进程优先(SJF)、时间片轮转(RR)等等。

linux 调用schedule函数 例子

linux 调用schedule函数 例子

linux 调用schedule函数例子Linux 调用 schedule 函数的例子在 Linux 内核中,schedule 函数是用于进行进程调度的重要函数。

它负责决定下一个要运行的进程,并切换到该进程的上下文。

下面是一个调用 schedule 函数的简单例子:```c#include <linux/sched.h>int main(void) {struct task_struct *next_task;// 调用 schedule 函数,选择下一个要运行的进程next_task = schedule();// 打印进程的 PIDprintk("Next scheduled task's PID: %d\n", next_task->pid);return 0;}```在上述例子中,我们首先包含了 `<linux/sched.h>` 头文件,该头文件包含了schedule 函数的声明。

然后,我们声明了一个指向 `task_struct` 结构体的指针`next_task`,它将用于保存调度函数返回的下一个进程。

接下来,我们调用了 schedule 函数,并将返回值赋给 `next_task`。

由于这是一个简单的示例,我们并没有传递任何参数给 schedule 函数,实际上,在实际的进程调度中,schedule 函数会根据一系列的调度策略和优先级来选择下一个要运行的进程。

最后,我们使用 printk 函数打印了下一个调度的进程的 PID。

需要注意的是,上述代码只是一个示例,无法在用户空间中直接运行。

在Linux 内核中调用 schedule 函数需要在合适的上下文中进行,通常在内核模块或调度程序的其他部分中执行。

通过了解 schedule 函数的用法及其在进程调度中的作用,我们可以更好地理解Linux 内核中的调度机制,并更好地进行系统性能优化和调试。

schedulex 调度原理

schedulex 调度原理

ScheduleX调度原理主要基于分布式执行框架和多种任务类型的特点。

在ScheduleX中,用户可以依赖SchedulerX-Worker这个jar包,通过SchedulerX2.0提供的编程模型,编写简单的几行代码就能实现一套高可靠可运维的分布式执行引擎。

该调度器能够根据用户任务的类型来区分调度策略,例如对于简单任务,SchedulerX会从当前已经接入的客户端机器集群中,随机选择一台进行触发调度;而对于复杂任务,会采用集群调度。

同时,如果用户任务是简单任务多机版,SchedulerX则使用的是集群调度。

为了应对集群环境下的并发访问和机器故障,SchedulerX还提供了容错机制。

当有任务触发时,SchedulerX会从当前已经接入的客户端机器集群中,随机选择一台进行触发调度。

这样既保证了负载均衡,又避免了单点故障。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

进程调度函数schedule()分析一.主要功能:实现进程的调度,从运行队列的链表中找到一个进程,然后进行分配。

可以由几个内核控制路径调用。

二.调用方式:1.当前进程不能获得必要资源而被阻塞,可以直接调用schedule()。

将current进程插入适当的等待队列,把状态改为TASK_INTERRUPTABLE或TASK_UNINTERRUPTABLE,然后调用schedule()。

一旦资源可用,就从等待队列删除current进程。

2.把current进程的TIF_NEED_RESCHED标志设置为1,由于会在恢复前检查这个标志的值,所以schedule()将在之后某个时间被明确调用,以延迟方式调用调度程序。

三. 功能分析:asmlinkage void schedule(void){struct schedule_data * sched_data;struct task_struct *prev, *next, *p;struct list_head *tmp;int this_cpu, c; //定义变量,*prev为调度之前进程,*next为调度之后进程spin_lock_prefetch(&runqueue_lock);BUG_ON(!current->active_mm);//current进程的active_mm为空,出错need_reshced_back;prev=current;//变量初始化this_cpu = prev->processor;(unlikely(in_interrupt())) {printk("Scheduling in interrupt\n");BUG();}//不能再中断程序中执行schedule(),否则会出错release_kernel_lock(prev, this_cpu);sched_data = & aligned_data[this_cpu].schedule_data;spin_lock_irq(&runqueue_lock);//释放内核锁,开this_cpu中断,并锁住runqueue队列/* move an exhausted RR process to be last.. */if (unlikely(prev->policy == SCHED_RR))//是否为轮转调度if (!prev->counter) {prev->counter = NICE_TO_TICKS(prev->nice);move_last_runqueue(prev);}//prev->counter为逐渐减少的进程时间配额,当为0时就从当前位置到runqueue 的末尾。

NICE_TO_TICKS将优先级别换算为时间配额,即恢复开始的时间配额switch (prev->state) {case TASK_INTERRUPTIBLE:if (signal_pending(prev)) {prev->state = TASK_RUNNING;break;}//查看当前状态,如果处于TASK_INTERRUPTIBLE且有信号等待处理,内核将状态设置为TASK_RUNNING,让其处理完default:del_from_runqueue(prev);case TASK_RUNNING:;}prev->need_resched = 0;//如果没有信号等待,从等待队列撤出;如果处在TASK_RUNNING 继续进行/** this is the scheduler proper:*/repeat_schedule:/** Default process to select..*/next = idle_task(this_cpu);//指向最佳候选c = -1000;//进程的综合权值list_for_each(tmp, &runqueue_head) {p = list_entry(tmp, struct task_struct, run_list);if (can_schedule(p, this_cpu)) {int weight = goodness(p, this_cpu, prev->active_mm);if (weight > c)//比较权值c = weight, next = p;}}//调度之前将要调度的进程默认为0号,权值为-1000。

0号进程即不会睡眠,也不会死亡。

内核遍历可执行队列runqueue的每个进程,用godness计算权值,然后进行比较/* Do we need to re-calculate counters? */if (unlikely(!c)) {struct task_struct *p;spin_unlock_irq(&runqueue_lock);//锁住runqueueread_lock(&tasklist_lock);//锁住进程的tasklistfor_each_task(p)//对每个进程执行操作p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice);read_unlock(&tasklist_lock);spin_lock_irq(&runqueue_lock);goto repeat_schedule;}//若c为0,说明运行队列中的所有权值都为0,要重新分配/** from this point on nothing can prevent us from* switching to the next task, save this fact in* sched_data.*/sched_data->curr = next;task_set_cpu(next, this_cpu);spin_unlock_irq(&runqueue_lock);//对队列解锁,开中断if (unlikely(prev == next)) {/* We won't go through the normal tail, so do this by hand */prev->policy &= ~SCHED_YIELD;goto same_process;} //如果选中是原来进程,则另外执行操作#ifdef CONFIG_SMP/** maintain the per-process 'last schedule' value.* (this has to be recalculated even if we reschedule to* the same process) Currently this is only used on SMP,* and it's approximate, so we do not have to maintain* it while holding the runqueue spinlock.*/sched_data->last_schedule = get_cycles();/** We drop the scheduler lock early (it's a global spinlock),* thus we have to lock the previous process from getting* rescheduled during switch_to().*/#endif /* CONFIG_SMP */kstat.context_swtch++;/** there are 3 processes which are affected by a context switch:** prev == .... ==> (last => next)** It's the 'much more previous' 'prev' that is on next's stack,* but prev is set to (the just run) 'last' process by switch_to().* This might sound slightly confusing but makes tons of sense.*/prepare_to_switch();{struct mm_struct *mm = next->mm;struct mm_struct *oldmm = prev->active_mm;if (!mm) {BUG_ON(next->active_mm);next->active_mm = oldmm;atomic_inc(&oldmm->mm_count);enter_lazy_tlb(oldmm, next, this_cpu);} else {BUG_ON(next->active_mm != mm);switch_mm(oldmm, mm, next, this_cpu);}//开始进程切换,如果是内核线程,借用prev的地址空间,如果是一般进程,切换到next的用户空间if (!prev->mm) {prev->active_mm = NULL;mmdrop(oldmm);}}//如果是内核线程,则释放地址空间,将mm_struct的共享计数减一。

/** This just switches the register state and the* stack.*/switch_to(prev, next, prev);__schedule_tail(prev);same_process:reacquire_kernel_lock(current);if (current->need_resched)goto need_resched_back;return;}//针对smp(smp是多处理机系统),如果调度标志位不为0,重新调度四.分析结论与体会:通过分析,了解到shedule()的运行过程,一些linux常见的变量以及库函数。

它的最主要作用就是从就绪进程中选择一个优先级最高的进程来代替当前进程运行。

由于内核的重要性,掌握理解其功能是编写任何设备驱动的必要条件。

相关文档
最新文档