进程调度函数schedule()分析

合集下载

schedule()函数

schedule()函数

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

五、总结。

操作系统概论考试题含参考答案

操作系统概论考试题含参考答案

操作系统概论考试题含参考答案一、单选题(共90题,每题1分,共90分)1、将一个进程的逻辑地址空间分成若干个大小相等的片,称为A、页表B、页框C、页D、页内碎片正确答案:C2、【】的优点是空闲区分布均匀、查找开销较小。

A、循环首次适应算法B、首次适应算法C、最快适应算法D、最佳适应算法正确答案:A3、操作系统内核的资源管理功能不包括A、设备管理B、进程管理C、存储器管理D、时钟管理正确答案:D4、自调度算法的缺点不包括A、瓶颈问题B、低效性C、线程切换频繁D、不利于提高CPU的利用率正确答案:D5、现代操作系统的特征不包括A、并发B、共享C、虚拟D、同步性正确答案:D6、【】是用于管理文件的系统文件。

A、目录文件B、字符设备文件C、正规文件D、块设备文件正确答案:A7、下列关于静态优先权的说法中,错误的是A、静态优先权调度算法可以使系统获得更好的调度性能B、静态优先权在创建时确定C、静态优先权值通常可以根据进程的类型、进程需要的资源数量和户的要求来设定D、静态优先权在进程的整个运行期间保持不变正确答案:A8、进程的基本状态不包括A、完成态B、就绪态C、执行态D、阻塞态正确答案:A9、下列关于进程的说法中,错误的是A、进程是由正文段和进程控制块共同组成的执行环境B、进程是允许并发执行的程序在某个数据集合上的运行过程C、正文段存放被执行的机器指令D、进程控制块存放程序的运行环境正确答案:A10、下列关于内存中地址映射的说法中,错误的是A、地址映射是指把程序的逻辑地址转变为物理地址的过程B、地址映射应在硬件的支持下完成C、在多道程序系统中,地址空间中的逻辑地址和内存中的物理地址是一致的D、由内存中的一系列单元所限定的地址范围称为内存空间,其中的地址称为物理地址正确答案:C11、进程切换使当前正在执行的进程成为被替换进程,出让其所使用的CPU,以运行被进程调度程序选中的新进程。

进程切换的第一个步骤是A、更新被替换进程的进程控制块B、将被替换进程的进程控制块移到就绪队列或阻塞队列C、修改进程状态,把执行态改为就绪态或者阻塞态D、保存包括程序计数器和其他寄存器在内的CPU上下文环境正确答案:D12、单道批处理系统的特点不包括A、顺序性B、自动性C、复杂性D、单道性正确答案:C13、在存储器的层次结构中,L3层是A、寄存器B、主存储器C、本地二级存储D、高速缓存正确答案:B14、下列关于进程状态的转换的说法中,错误的是A、进程状态可由执行态直接变为就绪态B、进程状态可以由就绪态直接变为执行态C、进程状态可以由阻塞态直接变为执行态D、进程状态可以由执行态直接变为阻塞态正确答案:C15、进程之间的高级通信机制不包括A、管道通信系统B、共享存储器系统C、共享处理器系统D、消息传递系统正确答案:C16、MS-DOS使用的磁盘分配方法是A、使用磁盘的链接表分配B、连续分配C、不连续分配D、使用内存的链接表分配正确答案:D17、下列关于存储器的说法中,错误的是A、主存暂时存放存储容量更大、速度更慢的磁盘上的数据B、主存的容量一般比高速缓存存储器大C、高速缓存存储器保存最常用的数据D、高速缓存存储器作为主存中数据和指令子集的缓冲区正确答案:C18、下列关于I/O通道的说法中,错误的是A、I/O通道是一种特殊的处理机B、I/O通道具有执行I/O指令的能力,并通过执行通道程序来控制I/O操作C、通道是中小型主机系统中专门用于I/O的专用计算机D、引入通道能够使CPU从控制I/O的任务中解脱,使CPU与I/O并行工作正确答案:C19、下列关于实时计算的说法中,正确的是A、实时计算的正确性仅依赖于系统计算的逻辑结果B、实时计算的正确性不仅依赖于系统计算的逻辑结果,还依赖于产生正确结果的时间C、实时计算的正确性不仅依赖于系统计算的逻辑结果,还依赖于系统计算所需要的存储空间D、实时计算的正确性仅依赖于系统计算产生正确结果的时间正确答案:B20、产生死锁的必要条件不包括A、不剥夺条件B、环路等待条件C、同步条件D、请求和保持条件正确答案:C21、通常,可执行程序以【】可执行文件的形式存储在磁盘上A、二进制B、十六进制C、八进制D、十进制正确答案:A22、【】用于接收从CPU发来的I/O命令或有关控制信息、设备状态。

schedule_timeout_uninterruptible意思

schedule_timeout_uninterruptible意思

schedule_timeout_uninterruptible意思schedule_timeout_uninterruptible指的是在Linux内核中的一种延时函数。

在多进程的操作系统中,进程的调度是由内核负责的。

当一个进程需要等待某些事件发生时,通常会使用延时函数来暂停它的执行,以便让其他进程有机会运行。

延时函数是一种让进程停止执行一段时间的机制。

schedule_timeout_uninterruptible函数允许进程在指定延时时间内等待某个事件的发生,而不会被其他中断打断。

这意味着即使有其他进程需要执行,也不会中断当前进程的等待状态。

schedule_timeout_uninterruptible函数通常用于处理一些需要等待的操作,例如文件输入/输出操作、网络传输等。

当一个进程需要等待某个操作完成后才能继续执行时,它可以使用schedule_timeout_uninterruptible函数来暂停自身的执行,并设置一个适当的等待时间。

在使用schedule_timeout_uninterruptible函数时,需要注意设置合适的延时时间。

如果设置的时间太短,可能导致进程无法完成等待的操作,从而导致错误或异常。

如果设置的时间太长,可能会造成进程的长时间等待,影响系统的性能。

除了schedule_timeout_uninterruptible函数,Linux内核还提供了其他类型的延时函数,如schedule_timeout、msleep、usleep等。

这些函数之间的主要区别在于它们是否可以被中断。

例如,schedule_timeout函数可以被其他中断打断,而schedule_timeout_uninterruptible函数则不会被打断。

在实际使用中,开发人员需要根据具体的场景来选择合适的延时函数。

如果一个进程的等待操作可以被其他中断打断,且需要及时响应其他事件,可以考虑使用schedule_timeout函数。

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 内核中的调度机制,并更好地进行系统性能优化和调试。

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用户身份运行程序或具有相应的权限。

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

python3 schedule用法 -回复

python3 schedule用法 -回复

python3 schedule用法-回复Python3中的`schedule`库是一个用于在指定时间间隔或特定事件发生时运行任务的库。

它提供了一种简单、方便的方法来管理任务的调度和执行。

本文将对`schedule`库的使用进行详细介绍,并提供具体的步骤来回答关于其用法的问题。

第一步- 安装`schedule`库:要使用`schedule`库,首先需要确保它已经安装在你的Python环境中。

可以通过使用以下命令来安装`schedule`库:shellpip3 install schedule这将在你的Python环境中安装`schedule`库。

第二步- 导入和创建`schedule`任务:一旦库被安装,你就可以在你的Python脚本中导入`schedule`库,并创建一个调度任务。

在脚本的顶部添加以下代码来导入库:pythonimport schedule然后,在你的脚本中创建一个要调度执行的函数。

例如,创建一个简单的函数来打印一条消息:pythondef my_task():print("Hello, World!")第三步- 定义调度计划:一旦你有了要执行的任务,你可以定义一个调度计划来指定何时运行这个任务。

`schedule`库提供了多种选项来定义调度计划。

以下是常用的一些选项:1. 每天执行一次任务:pythonschedule.every().day.do(my_task)2. 每周执行一次任务,指定星期几和时间:pythonschedule.every().wednesday.at("13:15").do(my_task)3. 每小时执行一次任务:pythonschedule.every().hour.do(my_task)4. 每分钟执行一次任务:pythonschedule.every().minute.do(my_task)以上只是一些常见的调度选项,`schedule`库还提供了更多高级的选项,例如在指定的日期执行任务等。

深入解读Linux进程调度Schedule【转】

深入解读Linux进程调度Schedule【转】

深⼊解读Linux进程调度Schedule【转】调度系统是现代操作系统⾮常核⼼的基础⼦系统之⼀,尤其在多任务并⾏操作系统(Multitasking OS)上,系统可能运⾏于单核或者多核CPU上,进程可能处于运⾏状态或者在内存中可运⾏等待状态。

如何实现多任务同时使⽤资源并且提供给⽤户及时的响应实现实时交互以及提供⾼流量并发等对现代操作系统的设计实现带来了巨⼤挑战,⽽Linux调度⼦系统的设计同样需要实现这些看似⽭盾的要求,适应不同的使⽤场景。

我们看到Linux是⼀个复杂的现在操作系统,各个⼦系统之间相互合作才能完成⾼效的任务。

本⽂从围绕调度⼦系统,介绍了调度⼦系统核⼼的概念,并且将其与Linux各个相关组件的关系进⾏探讨,尤其是与调度⼦系统息息相关的中断(softirq和irq)⼦系统以及定时器Timer,深⼊⽽全⾯地展⽰了调度相关的各个概念以及相互联系。

由于笔者最近在调试PowerPC相关的芯⽚,因此相关的介绍会以此为例提取相关的内核源代码进⾏解读展⽰。

涉及的代码为Linux-4.4稳定发布版本,读者可以查看源码进⾏对照。

1. 相关概念要理解调度⼦系统,⾸先需要总体介绍调度的流程,对系统有⼀个⾼屋建瓴的认识之后,再在整体流程中对各个节点分别深⼊分析,从⽽掌握丰富⽽饱满的细节。

在系统启动早期,会注册硬件中断,时钟中断是硬件中断中⾮常重要的⼀种,调度过程中需要不断地刷新进程的状态以及设置调度标志已决定是否抢占进程的执⾏进⾏调度。

时钟中断就是周期性地完成此项⼯作。

这⾥⼜引出另外⼀个现代OS的调度设计思想即抢占(preempt),⽽与其对应的概念则为⾮抢占或者合作(cooperate),后⾯会给出两者的详细区别。

时钟中断属于硬件中断,Linux系统不⽀持中断嵌套,所以在中断发⽣时⼜会禁⽌本地中断(local_irq_disable),⽽为了尽快相应其他可能的硬件事件,必须要尽快完成处理并开启中断,因此引出了中断下半部,也就是softirq的概念。

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" 模块。

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()函数。

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. }可见,调用了具体运行队列的删除函数,我们看最关键的选择下一个进程的方式。

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

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

操作系统实验报告--进程调度计科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)进程调度过程的结果:六、实验总结通过本实验使我对进程的相关概念及进程的优先数调度算法有了更深的理解,使自己在程序设计及编制方面也有了一定的提高。

内核开发3

内核开发3

Linux内核异常Linux进程调度Linux系统调用Proc文件系统Linux内核异常Linux进程调度Linux系统调用Proc文件系统进程状态5. TASK_KILLABLELinux2.6.25新引入的进程睡眠状态,原理类似于TASK_UNINTERRUPTIBLE, 但是可以被致命信号(SIGKILL)唤醒。

6. TASK_TRACED正处于被调试状态的进程。

嵌入式Linux技术咨询QQ号: 550491596 嵌入式Linux学习交流QQ群: 65212116进程状态7. TASK_DEAD进程退出时(调用do_exit),state字段被 设置为该状态。

嵌入式Linux技术咨询QQ号: 550491596 嵌入式Linux学习交流QQ群: 65212116进程状态v int exit_state /*进程退出时的状态*/ EXIT_ZOMBIE(僵死进程)表示进程的执行被终止,但是父进程还没有发布 waitpid()系统调用来收集有关死亡的进程的信息。

EXIT_DEAD(僵死撤销状态) 表示进程的最终状态。

父进程已经使用wait4()或 waitpid()系统调用来收集了信息,因此进程将由系 统删除。

嵌入式Linux技术咨询QQ号: 550491596 嵌入式Linux学习交流QQ群: 65212116进程状态嵌入式Linux技术咨询QQ号: 550491596 嵌入式Linux学习交流QQ群: 65212116进程描述v struct mm_struct *mm 进程用户空间描述指针,内核线程该指针为空。

v unsigned int policy 该进程的调度策略。

v int prio 优先级,相当于 2.4 中 goodness() 的计算结果,在0--(MAX_PRIO-1) 之间取值(MAX_PRIO 定义为 140),其中 0—(MAX_RT_PRIO-1) (MAX_RT_PRIO 定义为100)属于实时进 程范围,MAX_RT_PRIO-MX_PRIO-1 属于非实时进程。

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脚本:这些将作为外部操作系统任务运行。

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

进程调度实验报告源码

进程调度实验报告源码

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

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

二、实验环境操作系统: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调度算法按照进程的到达时间进行调度,可能导致短作业等待时间长,效率较低。

=5内核启动流程之(start_kernel()-rest_init()-cpu_idle() schedule() 0&1号进程)

=5内核启动流程之(start_kernel()-rest_init()-cpu_idle() schedule() 0&1号进程)

1) __lookup_processor_type(); 【查找处理器类型===位于arch/arm/kernel/head.S】2) __lookup_machine_type() ; 【查找机器类型】3) __vet_atags(); 【函数实现的就是判断r2是否是有效的tag列表指针,如果不是,就将零指针赋值给r2】4) __create_page_tables(); 【创建页表】5) __enable_mmu(); 【使能MMU】6) __mmap_switched(); 【拷贝数据,清BBS】decompress_kernel()【解压缩内核文件===位于arch/arm/boot/compressed/misc.c】7) start_kernel(); 【进入真正的内核初始化函数===位于init/main.c】…各种初始化函数…86) rest_init(); 【最后的初始化操作】87) cpu_idle(); 【函数会被调用来使系统处于闲置(idle)状态并等待用户程序的执行。

至此,整个Linux内核启动完毕!】【1】asmlinkage void __init start_kernel(void){…各种初始化函数…/* Do the rest non-__init'ed, we're now alive */rest_init();}【2】static noinline void __init_refok rest_init(void){int pid;rcu_scheduler_starting();//内核RCU锁机制调度启动,因为下面就要用到/** 我们必须先创建init内核线程,这样它就可以获得pid为1。

* 尽管如此init线程将会挂起来等待创建kthreads线程。

* 如果我们在创建kthreadd线程前调度它,就将会出现OOPS。

*/kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);//创建kernel_init内核线程,内核的1号进程!!!!!【此处创建init进程,就是韦东山342页的init_post()函数,参考”=5内核启动流程之(init_post())[在rest_init()中被调用].doc”】numa_default_policy();//设定NUMA系统的内存访问策略为默认pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);//创建kthreadd内核线程,它的作用是管理和调度其它内核线程。

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 库在单个进程中可管理的任务数量有限,当任务数量较多时,可能会影响程序的性能。

进程切换过程详解

进程切换过程详解

进程切换过程详解/*注:在学习内核的时候有⼀个困难,那就是任何⼀个模块都不是孤⽴的,⽐如进程的调度就设计到中断处理、信号处理还有进程上下⽂的切换等等。

作为⼀个初学者,想⼀下⼦把操作系统的整个运⾏过程都清晰地展现在脑海是不现实的。

尽管如此,每个模块还是有它所关注的焦点,我们所采取的策略是把整个操作系统分为⼏个⼤模块,⽐如:进程的管理、内存管理、⽂件系统等等。

然后把这些⼤模块进⼀步分解成⼀个个⼩模块,⽐如进程的管理可以细分为进程的创建、进程的切换、系统调⽤的处理、信号的处理等等。

在分析每⼀个模块时,先把其他的模块抽象化,千万不要陷⼊其他模块的细节当中,,也可以说这是⼀种各个击破的⽅法,当你把每个⼩模块的功能搞清楚后,到最后整个操作系统的运⾏过程就很清晰了!*/在上⼀篇博客中,我们提到当⼀个任务从系统调⽤处理函数返回之前会检查是否需要进⾏进程切换。

那么什么时候会发⽣进程的切换呢(任务调度)?当系统发⽣硬件中断、系统调⽤或者时钟中断时,就有可能发⽣进程的切换。

下⾯我们以时钟中断为例来看看进程的切换是如何进⾏的。

在此之前,我们先要做⼀个说明,由于我们并没有开始介绍进程的详细知识,对进程的详细介绍将放在进程的创建这⼀篇博客中(还没开始写O(∩_∩)O~),因此在这⾥我们先对进程做⼀个粗略的抽象:⼀个任务(就是进程)含有代码段、数据段、堆栈段,还有⼀个任务状态段TSS。

这个任务状态段TSS记录当前任务的所有状态信息,包括寄存器、系统参数等等。

TSS段的描述符放在TR寄存器中(也就是说访问TR就能访问当前任务的TSS段了)。

假设此刻CPU正在执⾏进程1,我们知道:系统有⼀个时钟频率,每隔⼀段时间就会发⽣⼀次时钟中断,这个时间段我们称为⼀个滴答。

假设经过了⼀个滴答,系统发⽣时钟中断,此时时钟中断处理程序就会被⾃动调⽤(timer_interrupt),timer_interrupt定义在kernel/System_call.s中,如下图所⽰:同我们上⼀篇讲的_system_call⼀样,它⾸先会执⾏⼀些保护现场的⼯作,接着在第189⾏代码中把_jiffies的值加1(_jiffies表⽰⾃系统启动以来经过的滴答数),接下来第192-194的代码将执⾏此次时钟中断的特权级CPL压⼊堆栈,⽤来作为后⾯do_timer的参数,接下来开始执⾏do_timer,do_timer函数定义在Kernel/Sched.c中,这个函数的主要作⽤是将当前进程的⽤户态执⾏时间或内核态执⾏时间加1,然后将当前进程的剩余时间⽚减1.如果当前进程的时间⽚还有剩余,那么直接return返回继续执⾏,接下来判断当前任务的CPL是否是0,如果是0,说明当前任务是在内核态被中断的,⽽Linux0.11中内核态是不能被抢占的,所以直接返回执⾏,如果不是0,则执⾏进程调度程序schedule()。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
case TASK_INTERRUPTIBLE:
if(signal_pending(prev))
{
prev->state = TASK_RUNNING;
break;
}//查看当前状态,如果处于TASK_INTERRUPTIBLE且有信号等待处理,内核将状态设置为TASK_RUNNING,//让其处理完
struct task_struct *prev, *next, *p;
struct list_head *tmp;
int this_cpu, c; //定义变量,*prev为调度之前进程,*next为调度之后进程
spin_lock_prefetch(&runqueue_lock);
} //若c为0,说明运行队列中的所有权值都为0,要重新分配
sched_data->curr = next;
task_set_cpu(next, this_cpu); spin_unlock_irq(&runqueue_lock);//对队列解锁,开中断
if (unlikely(prev == next))
{
prev->policy &= ~SCHED_YIELD;
goto same_process;
} //如果选中是原来进程,则另外执行操作
#ifdef CONFIG_SMP sched_data->last_schedule = get_cycles();
#endif /* CONFIG_SMP */
int weight = goodness(p, this_cpu, prev->active_mm);
if (weight > c)//比较权值
c = weight, next = p;
}
}//调度之前将要调度的进程默认为0号,权值为-1000。0号进程即不会睡眠,也不会死亡。内核遍历可执行队列runqueue的每个进程,用godness计算权值,然后进行比较
default: del_from_runqueue(prev);
case TASK_RUNNING:;
}
prev->need_resched = 0;//如果没有信号等待,从等待队列撤出;如果处在TASK_RUNNING继续进行 repeat_schedule:
next = idle_task(this_cpu);//指向最佳候选
BUG_ON(!current->active_mm);//current进程的active_mm为空,出错
need_reshced_back;
prev=current;//变量初始化 this_cpu = prev->processor;
(unlikely(in_interrupt()))
}
}//如果是内核线程,则释放地址空间,将mm_struct的共享计数减一。
switch_to(prev, next, prev);
__schedule_tail(prev);
same_process: reacquire_kernel_lock(current);
switch_mm(oldmm, mm, next, this_cpu);
}//开始进程切换,如果是内核线程,借用prev的地址空间,如果是一般进程,切换到next的用户空间
if (!prev->mm)
{
prev->active_mm = NULL;
mmdrop(oldmm);
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);
kstat.context_swtch++; prepare_to_switch();
{
struct mm_struct *mm = next->mm;
struct mm_struct *oldmm = prev->active_mm;
if (!mm)
{
spin_lock_irq(&runqueue_lock);//释放内核锁,开this_cpu中断,并锁住runqueue队列 if (unlikely(prev->policy == SCHED_RR))//是否为轮转调度
if (!prev->counter)
{
prev->counter = NICE_TO_TICKS(prev->nice);
p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice);
read_unlock(&tasklist_;
spin_lock_irq(&runqueue_lock);
goto repeat_schedule;
进程调度函数schedule()分析
一.主要功能: 实现进程的调度,从运行队列的链表中找到一个进程,然后进行分配。可以由几个内核控制路径调用。
二.调用方式: 1.当前进程不能获得必要资源而被阻塞,可以直接调用schedule()。将current进程插入适当的等待队列,把状态改为TASK_INTERRUPTABLE或TASK_UNINTERRUPTABLE,然后调用schedule()。一旦资源可用,就从等待队列删除current进程。
if (current->need_resched)
goto need_resched_back;
return;
}//针对smp(smp是多处理机系统),如果调度标志位不为0,重新调度 为以后编写linux设备驱动打下了良好基础。
2.把current进程的TIF_NEED_RESCHED标志设置为1,由于会在恢复前检查这个标志的值,所以schedule()将在之后某个时间被明确调用,以延迟方式调用调度程序。
三. 功能分析:
asmlinkage void schedule(void)
{
struct schedule_data * sched_data;
{
printk("Scheduling in interrupt\n"); BUG();
}//不能再中断程序中执行schedule(),否则会出错
release_kernel_lock(prev, this_cpu);
sched_data = & aligned_data[this_cpu].schedule_data;
if (unlikely(!c))
{
structtask_struct *p;
spin_unlock_irq(&runqueue_lock);//锁住runqueue
read_lock(&tasklist_lock);//锁住进程的tasklist
for_each_task(p)//对每个进程执行操作
c = -1000;//进程的综合权值
list_for_each(tmp, &runqueue_head)
{
p = list_entry(tmp, struct task_struct, run_list); if (can_schedule(p, this_cpu))
{
move_last_runqueue(prev);
}//prev->counter为逐渐减少的进程时间配额,当为0时就从当前位置到runqueue的末尾。NICE_TO_TICKS将优//先级别换算为时间配额,即恢复开始的时间配额
switch (prev->state)
{
相关文档
最新文档