Zephyr OS之内核调度

第2章    内核调度

2.1    线程调度概念

       zephyr内核是基于优先级抢占,时间片分配的实时操作系统。每当调度程序切换线程或当ISR打断当前线程运行时,内核首先保存当前线程的CPU寄存器值。当线程恢复运行时,这些寄存器值将被恢复。在操作系统术语里,称为切换上下文。

2.1.1    当前线程

       CPU当前正在运行的线程,称之为当前线程(current thread)。

2.1.2    线程优先级

       线程的优先级由一个有符号整型表示,值越小代表优先级越高。内核调度器总是选择优先级最高的就绪线程作为当前线程。当多个线程具有相同的优先级时,调度器选择等待时间最久的线程。

1)  优先级小于0的线程
       为协作式线程(cooprative thread), 这样的线程一旦成为了当前线程,将一直运行下去且不可被抢占,除非它主动释放CPU控制权让其它更高或相同优先级的线程得以运行。

2)  优先级大于或等于0的线程
       为抢占式线程(preemptible thread),这样的线程一旦成为了当前线程,允许被优先级更高的线程所抢占,当然它也可以通过锁定内核调度防止被抢占。同样,它也可以主动释放CPU控制权让相同优先级的其它线程得以运行。除此之外还允许采用时间片分配的方式,当在时间片用完时,调度器选择让相同优先级的其它线程得以运行。

       线程的初始优先级值可以在线程启动后动态地增加或减小。因此,通过改变线程的优先级,抢占式线程与协作式线程可互相转变。

2.1.3    线程状态

       准备运行的线程状态称之为就绪态,被阻塞的线程状态称之为非就绪态。 

       以下情况都可以使得线程成为非就绪态的线程:
1)  线程还未启动,例如线程创建时为延时启动
2)  线程正在等待某个内核服务对象,例如等待信号量
3)  线程正在等待超时服务, 例如睡眠一段时间
4)  线程被挂起、结束或终止 

2.2    锁住当前线程

void k_sched_lock(void)
void k_sched_unlock(void)

       如果抢占式线程希望在执行某个特殊的操作时不被抢占,它可以调用 k_sched_lock(),让调度器将其临时当做协作式线程,从而避免被抢占。一旦完成特殊操作,该线程应调用 k_sched_unlock(),以恢复其可抢占特性。

       在锁住情形下,如果线程主动释放CPU控制权,还是可以被切换到其它线程的。当恢复运行后,其锁住状态依旧有效。

2.3    线程忙等待

void k_busy_wait(uint32_t usec_to_wait) // 单位微秒

       线程可以调用k_busy_wait()延迟空运转一段时间, 但并不会放弃CPU的控制权。通常使用忙等待,而不是线程休眠的情形:当所需的延迟太短,无法及时让调度程序从当前线程切换到另一个线程,然后再切换回来。

2.4    线程主动释放CPU控制权

1)  调用k_yield()函数

void k_yield(void)

       此种方式将切换到其它更高或相同优先级的就绪态线程,如果不存在,将立即返回。但使用时有个问题:如果当前线程被切换到更高优先级的协作式线程后,就算高优先级的协作式线程调用k_yield(),也切换不回该线程。

2)  调用k_sleep()函数

void k_sleep(int32_t duration) // 单位毫秒

       此种方式让当前线程进入持续一段时间的睡眠非就绪状态。在该时间内允许其它任意优先级的线程得以运行。但这种情形下,低优先级的线程仍有可能得不到调度。

3)  调用内核服务
       此种方式通过调用内核相关的服务而暂时释放CPU控制权,例如等待信号量、队列消息、邮箱等。这方面的内容将在后面章节学习过程中逐一描述。

2.5    改变其它线程状态

1)  调用k_wakeup()函数

void k_wakeup(k_tid_t thread)

       用于唤醒一个正常睡眠的线程。

2)  调用k_thread_cancel()函数

int k_thread_cancel(k_tid_t thread)

       用于取消一个正在延时启动的线程。如果返回0表示取消成功,否则表示该线程已启动。

3)  调用k_thread_abort()函数

void k_thread_abort(k_tid_t thread)

       用于终止一个线程,被终止的线程永远不会再得到运行。

4)  调用k_thread_suspend()函数

void k_thread_suspend(k_tid_t thread)

       用于挂起一个线程,被挂起的线程暂时不会得到运行。

5)  调用k_thread_resume()函数

void k_thread_resume(k_tid_t thread)

       用于恢复一个被挂起的线程。

2.6    获取当前线程标识

k_tid_t k_current_get(void)

       常用于操作系统调试打印,线程监控等。

2.7    获取和更改线程优先级

int k_thread_priority_get(k_tid_t thread)
void k_thread_priority_set(k_tid_t thread, int prio)

2.8    设置抢占式线程时间片

void k_sched_time_slice_set(int32_t slice, int prio)

        用于设定调度程序允许当前线程的运行时间片大小。优先级高于prio的任何线程不适用时间片限制。要禁用时间片段,将sliceprio设置为零即可。

 

转载于:https://my.oschina.net/feigec/blog/884728

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值