zephyr笔记 2.1.2 线程的调度

标签: Zephyr
22人阅读 评论(0) 收藏 举报
分类:

我正在学习 Zephyr,一个很可能会用到很多物联网设备上的操作系统,如果你也感兴趣,可点此查看帖子zephyr学习笔记汇总

1 前言

Zephyr 使用基于优先级的调度器来让应用线程们共享CPU。

http://docs.zephyrproject.org/kernel/threads/scheduling.html

2 概念

2.1 线程状态

线程未就绪可能受如下影响:

  • 线程尚未启动。
  • 线程正在等待内核对象完成操作。(例如,线程正在使用不可用的信号量。)
  • 线程正在等待发生超时。
  • 该线程已被暂停。
  • 线程已终止或中止。

2.2 线程优先级

优先级是个整形值,可以是负的或者非负。数值越小,优先级越高。例如,优先级为4的线程A会比优先级为7的线程B拥有更高优先级,优先级为-2的线程C拥有比线程A和线程B更高的优先级。

  • 协作式线程使用负数优先级数值。一旦变为当前线程,协作线程将会持续保留,直到它执行动作进入未就绪状态。
  • 抢占式线程使用非负数优先级数值。一旦它变为当前线程,如果有协作式线程,或者更高或相等的抢占式线程进入就绪状态,当前抢占式线程将会被取代。

配置选项 CONFIG_NUM_COOP_PRIORITIES 以及 CONFIG_NUM_PREEMPT_PRIORITIES 指定不同类型线程的优先级等级数,限定如下的优先级范围:

  • 协作式线程: (-CONFIG_NUM_COOP_PRIORITIES) to -1
  • 抢占式线程: 0 to (CONFIG_NUM_PREEMPT_PRIORITIES - 1)

例如,把5个协作式线程的优先级设置为 -5 到 -1,以及抢占式线程的优先级设置为 0 到 9。

2.3 调度算法

内核调度器选择最高优先级的就绪线程作为当前线程。当有多个相同优先级的线程存在,调度器将会选择等最久的那个。

注意:ISR 将会优先于线程执行,因此当前线程可随时被ISR所取代。这适用于协作式线程和抢占式线程。

2.4 协作式线程的时间切片

如果协作式线程执行冗长的计算,将会导致其他线程出现不可接受的延迟,包括那些更高或相等的优先级。

为了解决这个问题,协作式线程可以不时地放弃CPU,以允许其他线程执行。线程放弃CPU有两种方式:

http://docs.zephyrproject.org/kernel/threads/scheduling.html#cooperative-time-slicing

Calling puts the thread at the back of the scheduler’s prioritized list of ready threads, and then invokes the scheduler.

  • 调用 k_yield() 可以把放到就绪线程列表的最后,然后执行调度器。所有更高优先级或者相等优先级的就绪线程将会先被执行。如果没有这样的就绪线程,那么调度器则会继续执行当前线程,无需做任务切换。

  • 调用 k_sleep() 使得线程在一段时间内为未就绪状态。

2.5 抢占式线程的时间切片

一旦抢占式线程成为当前线程,它会一直维持为当前线程,直到更高优先级的线程就绪,或者这个线程操作自己变成非就绪状态。因此,如果抢占式线程执行复杂运算,就可能导致其他线程(包括那些相同优先级的线程)的调度出现不可接受的延时。

为了解决这样的问题,抢占式线程可以执行协作式的时间切片(同上描述),或者调度器的时间切片能力可以允许相同优先级的线程执行。

调度器将时间分成一系列时间切片,切片是以系统时钟tick为单位。切片的长度是可配的。

在每个时间切片的末尾,调度器会检查当前线程是否是抢占式的,如果是的话,就会执行 k_yield()。这样给与其他相同优先级的其他就绪线程寄回。如果没有就绪的相等优先级线程,当前线程会继续维持为当前线程。

超过限定优先级的线程将会被排除在抢占式时间切片之外,以及不能被相同优先级的线程所抢占。这使得只在处理更低优先级且对时间不敏感的线程时,应用程序才能使用抢占式的时间切片。

内核的时间切片算法不能保证一系列优先级相等的线程可以获得相等的CPU时间,因为不能精确测量线程获得执行的时间。例如,一个线程可能在1个时间切片的末尾刚成为当前线程,接着直接被CPU放弃。算法可以保证,在没有被要求放弃的时候,线程绝不会执行超过1个时间切片。

2.6 调度锁定

在执行关键操作时不希望被抢占的可抢占线程可以通过调用k_sched_lock() 来指示调度器暂时将其视为协作线程。 这可以防止其他线程在关键操作执行时发生干扰。

一旦关键操作完成,可抢占线程就必须调用k_sched_unlock() 来恢复其正常的可抢占状态。

如果一个线程调用k_sched_lock() 并随后执行一个使其不准备的动作,调度器将切换锁定线程并允许其他线程执行。 当锁定线程再次成为当前线程时,将保持其不可抢占状态。

锁定调度程序对于可抢占线程来说是一种更有效的方法来禁止抢占,而不是将其优先级改为负值。

2.7 线程休眠

一个线程可以调用k_sleep() 来延迟一段指定的时间再处理。 在线程休眠期间,放弃CPU以允许其他就绪线程执行。 一旦经过指定的延迟时间,线程就会就绪,并可以被再次调度。

休眠线程可以使用k_wakeup()由另一个线程提前唤醒。 这种技术有时可用于让辅助线程发信号通知睡眠线程发生了某些事情,而不需要线程定义内核同步对象,例如信号量。 唤醒未睡眠的线程是允许的,但不起作用。

2.8 忙等待

一个线程可以调用k_busy_wait() 来执行一个忙等待,将其延迟一段指定的时间再处理,而不会放弃CPU到另一个就绪线程。
当所需延迟太短而不能保证调度程序上下文从当前线程切换到另一个线程,然后再返回时,通常使用忙等待来代替线程休眠。

3 建议用法

使用协作线程进行设备驱动程序和其他性能关键型工作。

使用协作线程来实现互斥,而不需要内核对象,例如互斥锁。

使用抢占式线程优先处理时间敏感的事务,而非时间不敏感的事务。

4 配置选项

  • CONFIG_NUM_COOP_PRIORITIES
  • CONFIG_NUM_PREEMPT_PRIORITIES
  • CONFIG_TIMESLICING
  • CONFIG_TIMESLICE_SIZE
  • CONFIG_TIMESLICE_PRIORITY

5 API

下列线程API,都在 kernel.h 中提供了:

k_current_get()
k_sched_lock()
k_sched_unlock()
k_yield()
k_sleep()
k_wakeup()
k_busy_wait()
k_sched_time_slice_set()

6 总结

抢占式线程要处理对时间敏感的时间,如果是关键任务,记得加锁。

如果线程处理中需要短暂延时,而不需要切换任务,那可以用忙等待接口。

End


查看评论

打通Linux脉络系列:进程、线程和调度

本课程分成4个组成部分,每次课60分钟。每次课后留下3~4个练习题,可以在微信群或者Linuxer公众号留言讨论答案和做题心得。
  • 2017年09月14日 17:16

Zephyr OS之内核调度

第2章    内核调度 2.1    线程调度概念        zephyr内核是基于优先级抢占,时间片分配的实时操作系统。每当调度程序切换线程或当ISR打断当前线程运行时,内核首先保存当前线程的...
  • lbaihao
  • lbaihao
  • 2017-04-24 22:17:46
  • 365

zephyr的执行上下文(多线程)

zepyhr的内核支持三种类型的多线程: 1、任务线程,可抢占,通常用来执行冗长和复杂的事务。任务的调度基于优先级,任务执行时高优先级任务抢占低优先级任务。 内核可选支持时间片轮转调度,也...
  • cn13512
  • cn13512
  • 2016-05-27 07:45:48
  • 737

uCos-iii 学习笔记开篇

uCos-iii 学习笔记开篇 一、基本概念         uCos-iii是一个可裁剪,可固化,可剥夺的多任务内核,没有任务数目的限制,其源代码开放,支持时间片轮转调度,系统API使用简单,易...
  • xianrenqiu90
  • xianrenqiu90
  • 2016-03-16 08:39:32
  • 1177

操作系统概念学习笔记 10 CPU调度

操作系统概念学习笔记 10CPU调度 多道程序操作系统的基础。通过在进程之间切换CPU,操作系统可以提高计算机的吞吐率。对于单处理器系统,每次只允许一个进程运行:任何其他进程必须等待,直到CPU空闲...
  • sunmc1204953974
  • sunmc1204953974
  • 2015-06-12 11:06:28
  • 3397

线程池和线程调度

1,线程池有一个缓冲队列:ArrayBlockingQueue final ThreadPoolExecutor threadPool = new ThreadPoolExecutor( ...
  • y41992910
  • y41992910
  • 2017-03-27 21:13:47
  • 778

线程调度的方法()

1 . sleep() 在睡眠的时候 会释放cpu 让给其他线程执行, 即使没有其他线程 抢占cpu 也需要等待睡眠时间到了以后才能真正的指定.package com.qf.demo3;public...
  • Myair_AC
  • Myair_AC
  • 2017-08-18 20:27:22
  • 873

Java线程: 线程调度

线程调度是Java多线程的核心,只有好的调度,才能充分发挥系统的性能,提高程序的执行效率。 一、休眠   休眠的目的是使线程让出CPU的最简单做法,线程休眠的时候,会将CPU交给其他线程,以便轮换...
  • arredando
  • arredando
  • 2017-08-04 14:47:20
  • 1055

zephyr学习笔记---前言

一直在找适合用于教学嵌入式操作系统。在我心目中,适合用于教学的操作系统应具备如下特点: 实时操作系统。了解实时操作系统,再去学习非实时操作系统,会更容易,反之不行。完全开源。规范的代码、详尽...
  • abatei
  • abatei
  • 2017-03-26 08:31:22
  • 3209

《Linux进程、线程和调度》4次课程高清ppt和录播链接

感谢报名《打通Linux脉络系列:进程、线程和调度》CSDN直播的300多位童鞋,感谢你们4*1小时的伴随,以及在微信群里热烈的技术讨论。 大纲: 《Linux的进程、线程以及调度》4节系列课...
  • juS3Ve
  • juS3Ve
  • 2017-10-06 00:00:00
  • 316
    个人资料
    持之以恒
    等级:
    访问量: 34万+
    积分: 4625
    排名: 7945
    微信公众号
      twowinter
    有眼光的朋友都扫了这里,
    欢迎在微信向我留言。
    最新评论