当前位置:首页 » 操作系统 » linux抢占

linux抢占

发布时间: 2022-12-08 11:55:27

linux内核执行进程调度的时机有哪些

Linux调度时机主要有:

1、进程状态转换的时刻:进程终止、进程睡眠。

2、当前进程的时间片用完时(current->counter=0)。

3、设备驱动程序。

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

时机1,进程要调用sleep()或exit()等函数进行状态转换,这些函数会主动调用调度程序进行进程调度。

时机2,由于进程的时间片是由时钟中断来更新的,因此,这种情况和时机4是一样的。

时机3,当设备驱动程序执行长而重复的任务时,直接调用调度程序。在每次反复循环中,驱动程序都检查need_resched的值,如果必要,则调用调度程序schele()主动放弃CPU。

时机4,如前所述,不管是从中断、异常还是系统调用返回,最终都调用ret_from_sys_call(),由这个函数进行调度标志的检测,如果必要,则调用调用调度程序。

从系统调用返回意味着要离开内核态而返回到用户态,而状态的转换要花费一定的时间,因此,在返回到用户态前,系统把在内核态该处理的事全部做完。

在Linux中,进程的运行时间不可能超过分配给他们的时间片,他们采用的是抢占式多任务处理,所以进程之间的挂起和继续运行无需彼此之间的协作。

在一个如linux这样的多任务系统中,多个程序可能会竞争使用同一个资源,在这种情况下,我们认为,执行短期的突发性工作并暂停运行以等待输入的程序,要比持续占用处理器以进行计算或不断轮询系统以查看是否有输入到达的程序要更好。

我们称表现好的程序为nice程序,而且在某种意义上,这个nice 是可以被计算出来的。操作系统根据进程的nice值来决定它的优先级,一个进程的nice值默认为0并将根据这个程序的表现不断变化。长期不间断运行的程序的优先级一般会比较低。

⑵ Linux系统的进程调度

Linux进程调度

1.调度方式

Linux系统的调度方式基本上采用“ 抢占式优先级 ”方式,当进程在用户模式下运行时,不管它是否自愿,核心在一定条件下(如该进程的时间片用完或等待I/O)可以暂时中止其运行,而调度其他进程运行。一旦进程切换到内核模式下运行时,就不受以上限制,而一直运行下去,仅在重新回到用户模式之前才会发生进程调度。

Linux系统中的调度基本上继承了UNIX系统的 以优先级为基础 的调度。也就是说,核心为系统中每个进程计算出一个优先级,该优先级反映了一个进程获得CPU使用权的资格,即高优先级的进程优先得到运行。核心从进程就绪队列中挑选一个优先级最高的进程,为其分配一个CPU时间片,令其投入运行。在运行过程中,当前进程的优先级随时间递减,这样就实现了“负反馈”作用,即经过一段时间之后,原来级别较低的进程就相对“提升”了级别,从而有机会得到运行。当所有进程的优先级都变为0(最低)时,就重新计算一次所有进程的优先级。

2.调度策略

Linux系统针对不同类别的进程提供了3种不同的调度策略,即SCHED_FIFO、SCHED_RR及SCHED_OTHER。其中,SCHED_FIFO适合于 短实时进程 ,它们对时间性要求比较强,而每次运行所需的时间比较短。一旦这种进程被调度且开始运行,就一直运行到自愿让出CPU或被优先级更高的进程抢占其执行权为止。

SCHED_RR对应“时间片轮转法”,适合于每次运行需要 较长时间的实时进程 。一个运行进程分配一个时间片(200 ms),当时间片用完后,CPU被另外进程抢占,而该进程被送回相同优先级队列的末尾,核心动态调整用户态进程的优先级。这样,一个进程从创建到完成任务后终止,需要经历多次反馈循环。当进程再次被调度运行时,它就从上次断点处开始继续执行。

SCHED_OTHER是传统的UNIX调度策略,适合于交互式的 分时进程 。这类进程的优先级取决于两个因素:一个是进程剩余时间配额,如果进程用完了配给的时间,则相应优先级降到0;另一个是进程的优先数nice,这是从UNIX系统沿袭下来的方法,优先数越小,其优先级越高。nice的取值范围是-20 19。用户可以利用nice命令设定进程的nice值。但一般用户只能设定正值,从而主动降低其优先级;只有特权用户才能把nice的值设置为负数。进程的优先级就是以上二者之和。

后台命令对应后台进程(又称后台作业)。后台进程的优先级低于任何交互(前台)进程的优先级。所以,只有当系统中当前不存在可运行的交互进程时,才调度后台进程运行。后台进程往往按批处理方式调度运行。

3.调度时机

核心进行进程调度的时机有以下5种情况:

(1)当前进程调用系统调用nanosleep( )或者pause( ),使自己进入睡眠状态,主动让出一段时间的CPU的使用权。

(2)进程终止,永久地放弃对CPU的使用。

(3)在时钟中断处理程序执行过程中,发现当前进程连续运行的时间过长。

(4)当唤醒一个睡眠进程时,发现被唤醒的进程比当前进程更有资格运行。

(5)一个进程通过执行系统调用来改变调度策略或者降低自身的优先级(如nice命令),从而引起立即调度。

4.调度算法

进程调度的算法应该比较简单,以便减少频繁调度时的系统开销。Linux执行进程调度时,首先查找所有在就绪队列中的进程,从中选出优先级最高且在内存的一个进程。如果队列中有实时进程,那么实时进程将优先运行。如果最需要运行的进程不是当前进程,那么当前进程就被挂起,并且保存它的现场—— 所涉及的一切机器状态,包括程序计数器和CPU寄存器等,然后为选中的进程恢复运行现场。

(二)Linux常用调度命令

· nohup命令

nohup命令的功能是以忽略挂起和退出的方式执行指定的命令。其命令格式是:

nohupcommand[arguments]

其中,command是所要执行的命令,arguments是指定命令的参数。

nohup命令告诉系统,command所代表的命令在执行过程中不受任何结束运行的信号(hangup和quit)的影响。例如,

$ nohup find / -name exam.txt -print>f1 &

find命令在后台运行。在用户注销后,它会继续运行:从根目录开始,查找名字是exam.txt的文件,结果被定向到文件f1中。

如果用户没有对输出进行重定向,则输出被附加到当前目录的nohup.out文件中。如果用户在当前目录中不具备写权限,则输出被定向到$HOME/nohup.out 中。

· at命令

at命令允许指定命令执行的时间。at命令的常用形式是:

attimecommand

其中,time是指定命令command在将来执行时的时间和日期。时间的指定方法有多种,用户可以使用绝对时间,也可以用相对时间。该指定命令将以作业形式在后台运行。例如:

$ at 15:00 Oct 20

回车后进入接收方式,接着键入以下命令:

mail -s "Happy Birthday!" liuzheny

按下D键,屏幕显示:

job 862960800.a at Wed Oct 20 15:00:00 CST 1999

$

表明建立了一个作业,其作业ID号是862960800.a,运行作业的时间是1999年10月20日下午3:00,给liuzheny发一条标题为“Happy Birthday!”(生日快乐)的空白邮件。

利用 at-l 可以列出当前at队列中所有的作业。

利用 at-r 可以删除指定的作业。这些作业以前由at或batch命令调度。例如,

at-r862960797.a

将删除作业ID号是862960797.a的作业。其一般使用形式是:

at-rjob_id

注意,结尾是.a的作业ID号,表示这个作业是由at命令提交的;结尾是.b的作业ID号,表示这个作业是由batch命令提交的。

· batch命令

batch命令不带任何参数,它提交的作业的优先级比at命令提交的作业的优先级低。batch无法指定作业运行的时间。实际运行时间要看系统中已经提交的作业数量。如果系统中优先级较高的作业比较多,那么,batch提交的作业则需要等待;如果系统空闲,则运行batch提交的作业。例如,

$ batch

回车后进入接收方式,接着键入命令:

find / -name exam.txt -print

按下D。退出接收方式,屏幕显示:

job 862961540.b at Thu Nov 18 14:30:00 CST 1999

表示find命令被batch作为一个作业提交给系统,作业ID号是862961540.b。如果系统当前空闲,这个作业被立即执行,其结果同样作为邮件发送给用户。

· jobs命令

jobs命令用来显示当前shell下正在运行哪些作业(即后台作业)。例如:

$ jobs

[2] + Running tar tv3 *&

[1] - Running find / -name README -print > logfile &

$

其中,第一列方括号中的数字表示作业序号,它是由当前运行的shell分配的,而不是由操作系统统一分配的。在当前shell环境下,第一个后台作业的作业号为1,第二个作业的作业号为2,等等。

第二列中的“ ”号表示相应作业的优先级比“-”号对应作业的优先级高。

第三列表明作业状态,是否为运行、中断、等待输入或停止等。

最后列出的是创建当前这个作业所对应的命令行。

利用 jobs-l 形式,可以在作业号后显示出相应进程的PID。如果想只显示相应进程的PID,不显示其它信息,则使用 jobs-p 形式。

· fg命令

fg命令把指定的后台作业移到前台。其使用格式是:

fg [job…]

其中,参数job是一个或多个进程的PID,或者是命令名称或者作业号(前面要带有一个“%”号)。例如:

$ jobs

[2] + Running tar tv3 *&

[1] - Running find / -name README -print > logfile&

$ fg %find

find / -name README -print > logfile

注意,显示的命令行末尾没有“&”符号。下面命令能产生同样的效果:

$ fg %1

这样,find命令对应的进程就在前台执行。当后台只有一个作业时,键入不带参数的fg命令,就能使相应进程移到前台。当有两个或更多的后台作业时,键入不带参数的fg,就把最后进入后台的进程首先移到前台。

· bg命令

bg命令可以把前台进程换到后台执行。其使用格式是:

bg [job…]

其中,job是一个或多个进程的PID、命令名称或者作业号,在参数前要带“%”号。例如,在cc(C编译命令)命令执行过程中,按下Z键,使这个作业挂起。然后键入以下命令:

$ bg %cc

该挂起的作业在后台重新开始执行。

⑶ linux 用户进程 可以抢占内核进程吗

1.2.1 调度过程中关闭内核抢占
我们在上一篇linux内核主调度器schele(文章链接, CSDN, Github)中在分析主调度器的时候, 我们会发现内核在进行调度之前都会通过preempt_disable关闭内核抢占, 而在完成调度工作后, 又会重新开启内核抢占
参见主调度器函数schele
do {
preempt_disable(); /* 关闭内核抢占 */
__schele(false); /* 完成调度 */
sched_preempt_enable_no_resched(); /* 开启内核抢占 */

} while (need_resched()); /* 如果该进程被其他进程设置了TIF_NEED_RESCHED标志,则函数重新执行进行调度 */123456123456

这个很容易理解, 我们在内核完成调度器过程中, 这时候如果发生了内核抢占, 我们的调度会被中断, 而调度却还没有完成, 这样会丢失我们调度的信息.
1.2.2 调度完成检查need_resched看是否需要重新调度
而同样我们可以看到, 在调度完成后, 内核会去判断need_resched条件, 如果这个时候为真, 内核会重新进程一次调度.
这个的原因, 我们在前一篇博客中, 也已经说的很明白了,
内核在thread_info的flag中设置了一个标识来标志进程是否需要重新调度, 即重新调度need_resched标识TIF_NEED_RESCHED, 内核在即将返回用户空间时会检查标识TIF_NEED_RESCHED标志进程是否需要重新调度,如果设置了,就会发生调度, 这被称为用户抢占
2 非抢占式和可抢占式内核
为了简化问题,我使用嵌入式实时系统uC/OS作为例子
首先要指出的是,uC/OS只有内核态,没有用户态,这和Linux不一样
多任务系统中, 内核负责管理各个任务, 或者说为每个任务分配CPU时间, 并且负责任务之间的通讯.
内核提供的基本服务是任务切换. 调度(Scheler),英文还有一词叫dispatcher, 也是调度的意思.
这是内核的主要职责之一, 就是要决定该轮到哪个任务运行了. 多数实时内核是基于优先级调度法的, 每个任务根据其重要程度的不同被赋予一定的优先级. 基于优先级的调度法指,CPU总是让处在就绪态的优先级最高的任务先运行. 然而, 究竟何时让高优先级任务掌握CPU的使用权, 有两种不同的情况, 这要看用的是什么类型的内核, 是不可剥夺型的还是可剥夺型内核
2.1 非抢占式内核
非抢占式内核是由任务主动放弃CPU的使用权
非抢占式调度法也称作合作型多任务, 各个任务彼此合作共享一个CPU. 异步事件还是由中断服务来处理. 中断服务可以使一个高优先级的任务由挂起状态变为就绪状态.
但中断服务以后控制权还是回到原来被中断了的那个任务, 直到该任务主动放弃CPU的使用权时,那个高优先级的任务才能获得CPU的使用权。非抢占式内核如下图所示.

非抢占式内核的优点有
中断响应快(与抢占式内核比较);
允许使用不可重入函数;
几乎不需要使用信号量保护共享数据, 运行的任务占有CPU,不必担心被别的任务抢占。这不是绝对的,在打印机的使用上,仍需要满足互斥条件。
非抢占式内核的缺点有
任务响应时间慢。高优先级的任务已经进入就绪态,但还不能运行,要等到当前运行着的任务释放CPU
非抢占式内核的任务级响应时间是不确定的,不知道什么时候最高优先级的任务才能拿到CPU的控制权,完全取决于应用程序什么时候释放CPU
2.2 抢占式内核
使用抢占式内核可以保证系统响应时间. 最高优先级的任务一旦就绪, 总能得到CPU的使用权。当一个运行着的任务使一个比它优先级高的任务进入了就绪态, 当前任务的CPU使用权就会被剥夺,或者说被挂起了,那个高优先级的任务立刻得到了CPU的控制权。如果是中断服务子程序使一个高优先级的任务进入就绪态,中断完成时,中断了的任务被挂起,优先级高的那个任务开始运行。
抢占式内核如下图所示

抢占式内核的优点有
使用抢占式内核,最高优先级的任务什么时候可以执行,可以得到CPU的使用权是可知的。使用抢占式内核使得任务级响应时间得以最优化。
抢占式内核的缺点有:
不能直接使用不可重入型函数。调用不可重入函数时,要满足互斥条件,这点可以使用互斥型信号量来实现。如果调用不可重入型函数时,低优先级的任务CPU的使用权被高优先级任务剥夺,不可重入型函数中的数据有可能被破坏。
3 linux用户抢占
3.1 linux用户抢占
当内核即将返回用户空间时, 内核会检查need_resched是否设置, 如果设置, 则调用schele(),此时,发生用户抢占.
3.2 need_resched标识
内核如何检查一个进程是否需要被调度呢?
内核在即将返回用户空间时检查进程是否需要重新调度,如果设置了,就会发生调度, 这被称为用户抢占, 因此内核在thread_info的flag中设置了一个标识来标志进程是否需要重新调度, 即重新调度need_resched标识TIF_NEED_RESCHED
并提供了一些设置可检测的函数

函数
描述
定义

set_tsk_need_resched 设置指定进程中的need_resched标志 include/linux/sched.h, L2920
clear_tsk_need_resched 清除指定进程中的need_resched标志 include/linux/sched.h, L2926
test_tsk_need_resched 检查指定进程need_resched标志 include/linux/sched.h, L2931
而我们内核中调度时常用的need_resched()函数检查进程是否需要被重新调度其实就是通过test_tsk_need_resched实现的, 其定义如下所示
// http://lxr.free-electrons.com/source/include/linux/sched.h?v=4.6#L3093
static __always_inline bool need_resched(void)
{
return unlikely(tif_need_resched());
}

// http://lxr.free-electrons.com/source/include/linux/thread_info.h?v=4.6#L106
#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED)1234567812345678

3.3 用户抢占的发生时机(什么时候需要重新调度need_resched)
一般来说,用户抢占发生几下情况:
从系统调用返回用户空间;
从中断(异常)处理程序返回用户空间
从这里我们可以看到, 用户抢占是发生在用户空间的抢占现象.
更详细的触发条件如下所示, 其实不外乎就是前面所说的两种情况: 从系统调用或者中断返回用户空间
时钟中断处理例程检查当前任务的时间片,当任务的时间片消耗完时,scheler_tick()函数就会设置need_resched标志;
信号量、等到队列、completion等机制唤醒时都是基于waitqueue的,而waitqueue的唤醒函数为default_wake_function,其调用try_to_wake_up将被唤醒的任务更改为就绪状态并设置need_resched标志。
设置用户进程的nice值时,可能会使高优先级的任务进入就绪状态;
改变任务的优先级时,可能会使高优先级的任务进入就绪状态;
新建一个任务时,可能会使高优先级的任务进入就绪状态;
对CPU(SMP)进行负载均衡时,当前任务可能需要放到另外一个CPU上运行
4 linux内核抢占
4.1 内核抢占的概念
对比用户抢占, 顾名思义, 内核抢占就是指一个在内核态运行的进程, 可能在执行内核函数期间被另一个进程取代.
4.2 为什么linux需要内核抢占
linux系统中, 进程在系统调用后返回用户态之前, 或者是内核中某些特定的点上, 都会调用调度器. 这确保除了一些明确指定的情况之外, 内核是无法中断的, 这不同于用户进程.
如果内核处于相对耗时的操作中, 比如文件系统或者内存管理相关的任务, 这种行为可能会带来问题. 这种情况下, 内核代替特定的进程执行相当长的时间, 而其他进程无法执行, 无法调度, 这就造成了系统的延迟增加, 用户体验到”缓慢”的响应. 比如如果多媒体应用长时间无法得到CPU, 则可能发生视频和音频漏失现象.
在编译内核时如果启用了对内核抢占的支持, 则可以解决这些问题. 如果高优先级进程有事情需要完成, 那么在启用了内核抢占的情况下, 不仅用户空间应用程序可以被中断, 内核也可以被中断,
linux内核抢占是在Linux2.5.4版本发布时加入的, 尽管使内核可抢占需要的改动特别少, 但是该机制不像抢占用户空间进程那样容易实现. 如果内核无法一次性完成某些操作(例如, 对数据结构的操作), 那么可能出现静态条件而使得系统不一致.
内核抢占和用户层进程被其他进程抢占是两个不同的概念, 内核抢占主要是从实时系统中引入的, 在非实时系统中的确也能提高系统的响应速度, 但也不是在所有情况下都是最优的,因为抢占也需要调度和同步开销,在某些情况下甚至要关闭内核抢占, 比如前面我们将主调度器的时候, linux内核在完成调度的过程中是关闭了内核抢占的.
内核不能再任意点被中断, 幸运的是, 大多数不能中断的点已经被SMP实现标识出来了. 并且在实现内核抢占时可以重用这些信息. 如果内核可以被抢占, 那么单处理器系统也会像是一个SMP系统
4.3 内核抢占的发生时机
要满足什么条件,kernel才可以抢占一个任务的内核态呢?
没持有锁。锁是用于保护临界区的,不能被抢占。
Kernel code可重入(reentrant)。因为kernel是SMP-safe的,所以满足可重入性。
内核抢占发生的时机,一般发生在:
当从中断处理程序正在执行,且返回内核空间之前。当一个中断处理例程退出,在返回到内核态时(kernel-space)。这是隐式的调用schele()函数,当前任务没有主动放弃CPU使用权,而是被剥夺了CPU使用权。
当内核代码再一次具有可抢占性的时候,如解锁(spin_unlock_bh)及使能软中断(local_bh_enable)等, 此时当kernel code从不可抢占状态变为可抢占状态时(preemptible again)。也就是preempt_count从正整数变为0时。这也是隐式的调用schele()函数
如果内核中的任务显式的调用schele(), 任务主动放弃CPU使用权
如果内核中的任务阻塞(这同样也会导致调用schele()), 导致需要调用schele()函数。任务主动放弃CPU使用权
内核抢占,并不是在任何一个地方都可以发生,以下情况不能发生
内核正进行中断处理。在Linux内核中进程不能抢占中断(中断只能被其他中断中止、抢占,进程不能中止、抢占中断),在中断例程中不允许进行进程调度。进程调度函数schele()会对此作出判断,如果是在中断中调用,会打印出错信息。
内核正在进行中断上下文的Bottom Half(中断下半部,即软中断)处理。硬件中断返回前会执行软中断,此时仍然处于中断上下文中。如果此时正在执行其它软中断,则不再执行该软中断。
内核的代码段正持有spinlock自旋锁、writelock/readlock读写锁等锁,处干这些锁的保护状态中。内核中的这些锁是为了在SMP系统中短时间内保证不同CPU上运行的进程并发执行的正确性。当持有这些锁时,内核不应该被抢占。
内核正在执行调度程序Scheler。抢占的原因就是为了进行新的调度,没有理由将调度程序抢占掉再运行调度程序。
内核正在对每个CPU“私有”的数据结构操作(Per-CPU date structures)。在SMP中,对于per-CPU数据结构未用spinlocks保护,因为这些数据结构隐含地被保护了(不同的CPU有不一样的per-CPU数据,其他CPU上运行的进程不会用到另一个CPU的per-CPU数据)。但是如果允许抢占,但一个进程被抢占后重新调度,有可能调度到其他的CPU上去,这时定义的Per-CPU变量就会有问题,这时应禁抢占。

⑷ linux是抢占式还是非抢占式

linux是抢占式的操作系统。现在普通用户使用的操作系统都是抢占式的操作系统。
另外,分为内核抢占和用户 抢占,linux2.4的内核支持内核抢占不支持用户抢占,2.6的内核都支持,

⑸ linux里的抢占-preempt

1. 什么是抢占?

抢占就是进城切换, 以thread_info->preempt_count标识。

thread_info->preempt_count一物多用:

bit0-7代表的是抢占的次数,最大抢占深度为256次,

bit8-15代表的是软中断的次数,最大也是256次,

bit16-19表示中断的次数,注释的大概意思是避免中断嵌套,但是也不能防止某些驱动中断嵌套使用中断,所以嵌套16层也是最大次数了。

bit20~23代表的NMI中断

2.抢占的函数:

spin_lock()/spin_unlock()

disable_preempt()/enable_preempt()--禁止或使能内核抢占,调用下面的inc_preempt_count()/dec_preempt_count(),加了memory barrier。

inc_preempt_count()/dec_preempt_count()

get_cpu()/put_cpu()

3.调度点

a) 进程被阻塞时

b) 调整参数时,比如通过sched_setscheler() ,nice()等函数调整进程的调度策略,静态优先级时

c) 睡眠进程被唤醒时,比如wake_up唤醒等待队列中的进程时,如果该进程具有更高优先级则会设置当前

  进程TIF_NEED_RESCHED,如果允许内核态抢占,则会调度一次

d)中断处理完时,如果中断处理过程中设置了TIF_NEED_SCHED标志,中断返回时,不论是要返回内核态还是用户态,都会发生一次抢占.当然,在这也会检查有没有软中断需要处理。

e)执行了preempt_enable()函数。

⑹ linux进程处于内核态会被更高优先级抢占吗

内核态抢占(Kernel
Preemption)
在2.6
kernel以前,kernelcode(中断和系统调用属于kernel
code)会一直运行,直到code被完成或者被阻塞(系统调用可以被阻塞)。在
2.6kernel里,Linuxkernel变成可抢占式。当从中断处理例程返回到内核态(kernel-space)时,kernel会检查是否可以抢占和是否需要重新调度。kernel可以在任何时间点上抢占一个任务(因为中断可以发生在任何时间点上),只要在这个时间点上kernel的状态是安全的、可重新调度的。

热点内容
逍遥模拟器如何配置网络 发布:2024-05-06 12:21:38 浏览:982
服务器如何检测硬件地址 发布:2024-05-06 12:12:35 浏览:738
服务器在线访问数由什么决定 发布:2024-05-06 11:39:15 浏览:678
途观21款哪个配置值得买 发布:2024-05-06 11:29:00 浏览:92
pythonspyder 发布:2024-05-06 11:15:53 浏览:166
线上服务器如何资源监控 发布:2024-05-06 11:15:07 浏览:299
页游脚本检测 发布:2024-05-06 11:05:05 浏览:925
七七网源码 发布:2024-05-06 10:27:36 浏览:295
shell输入脚本 发布:2024-05-06 10:19:49 浏览:985
通达信自定义板块在哪个文件夹 发布:2024-05-06 09:56:37 浏览:104