Linux进程调度

说明如下引用代码对应的kernel版本是2.6.34

I. Linux进程调度的函数schedule,先看一下schedule的实现。

/*
 * schedule() is the main scheduler function.
 */
asmlinkage void __sched schedule(void)
{
	struct task_struct *prev, *next;
	unsigned long *switch_count;
	struct rq *rq;
	int cpu;

need_resched:
	preempt_disable();//禁止抢占,实际操作是将current_thread_info的preempt_count加1,其他进程/线程不会抢占当前线程了
	cpu = smp_processor_id();//获取当前CPU号,逻辑CPU号
	rq = cpu_rq(cpu);  // 获取当前CPU的runqueue队列,该CPU上所有就绪状态的进程放在该队列中
	rcu_sched_qs(cpu); //
	prev = rq->curr;
	switch_count = &prev->nivcsw;

	release_kernel_lock(prev);//如果当前进程持有big kernel lock锁则释放,因为当前进程要切换出去了,不能占有该锁
need_resched_nonpreemptible:

	schedule_debug(prev);

	if (sched_feat(HRTICK))
		hrtick_clear(rq);

	spin_lock_irq(&rq->lock);//runqueue队列加锁
	update_rq_clock(rq);
	clear_tsk_need_resched(prev);//清除标志TIF_NEED_RESCHED
        
	if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {/*如果当前进程非就绪,并且没有被抢占*/

		if (unlikely(signal_pending_state(prev->state, prev)))//如果当前进程是task_interruptible或者有信号送达,状态更改为就绪
			prev->state = TASK_RUNNING;
		else
			deactivate_task(rq, prev, 1); //将当前进程从就绪队列中摘除;非就绪进程怎么会在就绪队列中?就绪任务在获取锁或者主动睡眠时将任务状态修改为非就绪,但是没有立即从就绪队列中出队列,此时才出队列

		switch_count = &prev->nvcsw;
	}

	pre_schedule(rq, prev);

	if (unlikely(!rq->nr_running))//如果运行队列上进程数是0,则先通过idle_balance函数从其他CPU上调度,进行负载均衡
		idle_balance(cpu, rq);      
       /*put_prev_task->put_prev_task_fair->put_prev_entity->__enqueue_entity将要调度出去的任务插入红黑树,当然插入红黑树的任务是R状态的,即没有被从就绪队列中摘除的*/
       put_prev_task(rq, prev);
       next = pick_next_task(rq);//挑选下一个要运行的进程将其排进就绪队列,挑选原则是选择红黑树上的最左边节点进程

    if (likely(prev != next)) {
        sched_info_switch(prev, next);
        perf_event_task_sched_out(prev, next, cpu); 

        rq->nr_switches++;//队列切换次数更新
        rq->curr = next; 
        ++*switch_count;//进程切换次数更新

        context_switch(rq, prev, next); /* unlocks the rq *///进程之间上下文切换
        /*    
         * the context switch might have flipped the stack from under
         * us, hence refresh the local variables.
         */
        cpu = smp_processor_id();
        rq = cpu_rq(cpu);
    } else
        spin_unlock_irq(&rq->lock);

    post_schedule(rq);

    if (unlikely(reacquire_kernel_lock(current) < 0)) 
        goto need_resched_nonpreemptible;

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


可见schedule的作用是将当前进程从就绪队列摘除,从就绪队列中选择一个其他符合条件的进程调度运行。何谓符合条件,后面详细分解。其中if (prev->state && !(preempt_count() & PREEMPT_ACTIVE))条件判断中的抢占计数如果PREEMPT_ACTIVE置位对应场景是当前进程被抢占了,此时不再从就绪队列中摘除当前进程,直接调度当前进程释放CPU,以加快选择下一个进程。

II. 哪些场景调用schedule进行调度呢?即调度时机有哪些?汇总如下,后面针对每种场景结合代码分析。

1. 中断,异常

2. 进程退出,睡眠

3. 进程创建,被唤醒,优先级改变时

4. 进程阻塞,如阻塞在信号量,互斥锁

其中2是进程主动调度,其他是被动调度。

III. 概念辨析

1. 禁止抢占就是禁止调度吗?

    看到许多资料提到禁止抢占就意味着禁止调度,何解?首先禁止抢占是针对进程(线程)来说的,所以标题的意思是禁止本进程的抢占意味着本进程不可调度了,和内核抢占配置CONFIG_PREEMPT宏不要混淆,配置宏打开意思是内核态可以抢占,是对所有进程而言的。进程A切换到进程B,有两种情况,一 A主动出让CPU 称作yielding,二 A被调度出让CPU称作preemption,两种都是调度,如果禁止抢占,即是禁止了preemption调度。


参考:http://blog.csdn.net/su_linux/article/details/15500053

http://blog.csdn.net/gatieme/article/details/51872618


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux 进程调度是指系统内核在多个进程之间调度 CPU 时间片的过程。它根据各种调度算法和优先级来决定每个进程获得 CPU 时间的顺序。常见的 Linux 调度算法有 Completely Fair Scheduler(CFS)和 Round Robin。 CFS 是 Linux 默认的调度算法,它根据每个进程的运行时间和优先级来决定调度顺序。 ### 回答2: Linux进程调度是操作系统对于进程的管理和分配资源的算法。在Linux系统中,进程是运行程序的实体,而进程调度则是决定进程运行顺序和时间的机制。 Linux采用了基于优先级的进程调度算法,通过动态地调整进程的优先级来决定进程被选中的概率。Linux内核中定义了两种进程调度策略:一种是实时调度策略,包括FIFO(先进先出)和RR(时间片轮转);另一种是非实时调度策略,包括CFS(完全公平调度)。 在实时调度策略中,FIFO按照进程进入系统的先后顺序进行调度,时间片由进程自行声明。而RR则将时间分成固定大小的时间片,每个进程只能运行一个时间片,然后切换到下一个进程。这两种调度策略主要适用于对实时性要求较高的应用。 而在非实时调度策略中,CFS采用了完全公平调度算法。CFS通过计算进程的虚拟运行时间,并将其与其他进程进行比较,从而确定下一个被调度进程。CFS倾向于将CPU时间平均地分配给每个进程,并避免某个进程独占CPU资源。 另外,Linux还引入了时间片的概念。时间片是CPU分配给每个进程的最小时间单位,它的大小直接影响着进程调度顺序。时间片越小,进程切换的频率就越高,系统的响应速度也会更快。 总的来说,Linux进程调度根据进程的优先级、类型和运行状态等因素,动态地为每个进程分配CPU资源,从而实现多任务的并发执行,提高系统的整体性能和响应速度。 ### 回答3: Linux进程调度是操作系统中重要的组成部分,它负责决定在多个进程同时运行时,每个进程被分配CPU的时间片长短和优先级。Linux通过采用时间片轮转和优先级调度的方式来管理进程。 时间片轮转调度算法是一种公平的调度方法,它将CPU的运行时间划分成较小的时间片,并按照轮转的方式分配给每个进程。当一个进程的时间片用完后,它会被放到就绪队列的末尾,等待下一次调度。这种调度方式保证了每个进程能够公平地使用CPU资源,避免了某些进程长时间占用CPU的情况。 Linux还采用了优先级调度算法,每个进程都有一个优先级值,数值越高表示优先级越高。在就绪队列中,调度器会将优先级最高的进程分配给CPU执行。如果两个进程的优先级相同,那么按照时间片轮转的方式进行调度。通过设定不同的进程优先级,可以实现进程的优先级控制和资源分配。 此外,Linux还引入了实时调度策略,包括实时先进先出和实时循环调度。实时调度算法是为了满足对实时任务有严格响应时间要求的场景,保证实时任务能够及时地被执行。 总结来说,Linux进程调度通过时间片轮转和优先级调度的方式,保证了进程的公平性和高优先级任务的及时响应能力。同时,引入实时调度策略,满足对实时任务的特殊需求。这些调度算法的运作机制和相互配合,为Linux操作系统的稳定性和高效性提供了重要的保障。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值