进互联网公司操作系统和网络库是基础技能,面试过不去的看,这里基于嵌入式操作系统分几章来总结一下任务调度、内存分配和网络协议栈的基础原理和代码实现。

处理器上电时会产生一个复位中断,接下来会执行复位中断服务函数,这才是软件执行的起始点。复位函数先后调用SystemInit和__main函数,SystemInit是处理器自带的库函数,一般执行各种时钟和外设的初始化;__main函数执行C语言运行环境的初始化,包括将目标程序从flash搬运到RAM、初始化全局变量等内存段初值,初始化C语言库函数等操作,最后跳转到main函数,执行用户程序。不同型号的处理器启动流程不太一致,如果不是需要设计bootloader,可以没必要关心。

mian的主要工作大致为:内存初始化、硬件中断初始化,此外还会分配基础的资源如锁、信号量等,最后创建idletask。idletask任务优先级最低,里面一般循环执行WFI指令使芯片保持低功耗状态。

任务相关结构初始化很简单,主要是分配任务块空间,并挂接在freelist链表上。后续分配任务时,从freelist链表上取就行。

接下来看看任务创建的步骤:

首先将需要回收的任务资源挂在freetasklist上去。这里是尽量延迟了任务的回收时间,不是在任务该回收的时候而是在新任务创建的时候回收旧任务。这样可以尽量减少CPU占用。所以每次新建任务,都是从freetasklist链表上取一个TCB下来然后根据用户需求分配栈大小,设置任务优先级和入口函数等。这里要注意操作freetasklist的过程中要关闭中断,防止操作过程中来了中断引起任务调度,导致crash。这里写代码需要注意因为参数检查、分配内存等流程都有可能出错,在设计程序的时候最好统一收口,所有错误有一个统一的出口处理,这样可以防止遗忘开中断等重要操作。大致流程如下:

从freelist头部摘取一个任务块,并分配任务栈空间、设置优先级等,新创建的任务需要挂接到priqueue链表数组中等待任务调度:

这里有个小知识点,一般的链表指向的都是结构体的首部,这样可以将链表指针直接强制转换成对应的数据结构(这里是任务块)。而在任务队列中链表位于任务块结构体中间,需要用宏来获取到链表指针对应的任务块首地址,这个宏的实现大同小异,各个操作系统都是借鉴Linux来实现的,详情百度:list_entry。

接下来就要说说操作系统是怎么做到常数级的任务切换时间的。初学者写的操作系统任务调度功能时可能会出现一种场景,那就是任务量少的时候任务切换时间快,任务量多的时候任务切换时间变慢,这种任务切换耗时不确定对用户任务影响时非常大的。我们来看看ucos系统是如何设计来保证常数级任务切换时间的。

一个全局的priqueue链表数组,上面挂接ready状态的任务队列,一个全局int32数,用于标记某优先级是否有需要调度的队列。要扩展到128位优先级也非常方便,设置4个int32数组即可。每次取优先级最高的任务,直接用CLZ汇编命令从bitmap中读出需要调度的最高优先级任务。

插入ready任务的时候需要将bitmap对应位置1,任务从ready状态移除的时候需要检查该优先级是否还有需要调度的任务,如果没有了,bitmap对应位需要置0。讲完嵌入式操作系统的进程调度,再来看看Linux的CFS的基础原理,就好理解多了,嵌入式系统低优先级队列可能会存在饿死现象,Linux的CFS调度算法给每个优先级分配了不同权重,根据就绪队列里所有任务的权重之和来分配任务的时间,来保证完全公平调度。

内存分配

前面分配任务块、分配任务栈等都用到了内存分配动作,具体的内存分配算法有:best-fit算法、TLSF算法、LWIP中的最快匹配算法、伙伴算法等,基础原理类似,下期再分析。

时钟中断

适配操作系统首要任务就是把时钟tick给起起来,这是芯片的心跳,所有的任务切换和延时操作都是基于时钟tick中断驱动的。

以ARM芯片的Cortex-M3核为例,启动时钟中断主要是调用osSetVector将tick回调函数设置进中断向量表里面的15号中断:

中断向量表长这样子:

前面15个中断号属于系统中断,后面预留中断号可供用户配置,M3是240个,M0是32个。

结合PendSV中断,可以在tick中断中完成别的事物(如定时器处理等),通过低优先级的PendSV中断来执行任务切换动作,从而减少中断响应时间。具体的分析在之前文章中:嵌入式操作系统的任务调度

在设置tick中断的时候还需要配置systick定时器的中断间隔。systick定时器是个简单的向下计数的24位计数器,寄存器位置位于系统控制空间基址SysTick_BASE偏移16字节,将需要的频率数值写入即可。systick寄存器的内部细节为:

详情可参考《ARM Cortex-M3 Cortex-M4权威指南》9.5节systick相关部分,其余相关linux中断知识可参考:Linux中断编程

顺带说一下,如果职业规划是往互联网方向转,那么寄存器硬件知识了解即可。如果想在物联网嵌入式领域深耕,不同ARM芯片之间的区别是一定要掌握的。

我们可以给tick中断配置为每10ms中断一次,防止过多的任务上下文切换占用CPU资源。中断到来后系统都要处理哪些事务呢?通常情况下会维护一个全局计数器,该中断到来时变量自增,然后会处理定时器任务和超时任务。

超时任务是什么呢?比如用户任务等待某个资源(锁、信号量等),如果获取不到就会设置超时时间阻塞等待,直到资源可用或者任务超时。因此每次时钟中断到来都需要判断是否有任务超时。

定时器任务就比较简单了,可以使用全局链表有序挂接定时任务,每次只需要判断链表头的任务是否到时,到时了摘取下来执行对应的回调函数即可。

不同的操作系统可能会在tick中断里面做一些别的事情,比如定时器对齐等。

貌似还有很多没写完,下周末再来总结。最后推荐嵌入式操作系统入门的三本书:《嵌入式操作系统内核调度--底层开发者手册》、《嵌入式网络那些事--STM32物联实战》、《ARM Cortex-M3 Cortex-M4权威指南》

优先级调度算法实现_一篇讲透嵌入式操作系统任务调度相关推荐

  1. 并发执行变成串行_一篇讲透如何理解数据库并发控制(纯干货)

    1.数据库并发控制的作用 1.1 事务的概念 在介绍并发控制前,首先需要了解事务.数据库提供了增删改查等几种基础操作,用户可以灵活地组合这几种操作,实现复杂的语义.在很多场景下,用户希望一组操作可以做 ...

  2. 并发执行变成串行_一篇讲透如何理解数据库并发控制

    01数据库并发控制的作用 1.1 事务的概念 在介绍并发控制前,首先需要了解事务.数据库提供了增删改查等几种基础操作,用户可以灵活地组合这几种操作,实现复杂的语义.在很多场景下,用户希望一组操作可以做 ...

  3. 百度排名批量查询_一篇讲透百度霸屏引流细节思路与操作玩法

    废话不多说,我们今天来聊聊百度霸屏引流这件事: 现在外面所讲的百度霸屏就这几个操作步骤,当然也就这几个步骤,再多也没什么了,简单看下哈: 第一点:选择高权重平台并注册 第二点:挖掘大量长尾词 第三点: ...

  4. itstime后面跟什么_一文讲透什么是引流

    这个问题老生常谈,都快腻了,还是有人时不时问老马.究其原因,很多人从想做引流.到动手操作,整个流程都是懵逼的状态. 引流不难,难的是一直卡在某个阶段,或者一直停留在那里.这样,你做再多次引流,还是患得 ...

  5. 10自带sftp服务器_一文讲透FTP和SFTP的区别

    阅读本文约需要10分钟,您可以先关注我们或收藏本文,避免下次无法找到. FTP和SFTP都是文件传输协议,我们知道FTP使用的是20和21端口,SFTP使用的是22端口.另外,SFTP前面的S应该是S ...

  6. 优先级调度算法动态优先级_与优先级调度有关的问题及其解决方案

    优先级调度算法动态优先级 We are already familiar with what Priority Scheduling is. It is one of the most used pr ...

  7. 双线macd指标参数最佳设置_一文讲透双线MACD指标及其实战运用

    原标题:一文讲透双线MACD指标及其实战运用 船长的舍得交易体系技术理论模型中,我们要用到两大指标,分别是均线系统和双线MACD指标. 很多小伙伴都喜欢用双线MACD这个指标,但是90%的人都不知道其 ...

  8. 优先级调度算法实现_《操作系统原理》实验一:进程调度

    操作系统原理实验-进程调度实验报告 一.目的与要求 (1)进程是操作系统最重要的概念之一,进程调度是操作系统内核的重要功能,本实验选用XX语言编写了一个进程调度模拟程序,使用优先级或时间的轮转法实现进 ...

  9. 嵌入式操作系统_一个C++版的嵌入式操作系统

    现世面上流传着很多嵌入式操作系统,都已经非常优秀,但本人(Sam的博客-博客园)还是自己编写了一个RTOS,不敢说优秀,但绝对是使用起来最简单的.先看一个工程截图与一段main.cpp代码 #incl ...

最新文章

  1. 【地图API】收货地址详解2
  2. python学费多少-培训python学费多少?
  3. amd显卡风扇调节_和AMD首席游戏架构师Frank Azor聊聊RX 6000系列显卡那些事儿
  4. HTTP请求报文和HTTP响应报文(转载)
  5. 京东也不甘当当后!买书4折优惠!
  6. c51倒计时程序汇编语言,51单片机汇编程序:倒计时交通灯
  7. mysql 汇总行_MySQL查询汇总行的值并对结果进行排序?
  8. 2015蓝桥杯省赛---java---C---2(立方尾不变)
  9. 马大为院士:科研人也得养家, 非升即走压力下,不得不做短平快的研究
  10. linux的多任务 多进程,浅谈linux模拟多线程崩溃和多进程崩溃
  11. Transformer-XL语言模型:超长上下文依赖
  12. dqn在训练过程中loss越来越大_深度强化学习——从DQN到DDPG
  13. Telerik for AJAX RadGrid控件
  14. 基于hydra的ssh密码的暴力破解
  15. 小米系统服务器,小米服务框架
  16. iOS gmssl 编译
  17. chrome os 安装手册
  18. PDF 文档拆分工具包
  19. 关掉该死的DEP(数据执行保护,仅针对win7)
  20. Win10 VC++运行库集合|VC++ 2005 2008 2010 2012 2015

热门文章

  1. Android无线调试出现错误的解决方法
  2. java设计模式之外观模式(门面模式)
  3. Spring MVC - Hello World示例
  4. 大量多风格多功能后台管理模板
  5. PHP7 serialize_precision 配置不当导致 json_encode() 浮点小数溢出错误
  6. 【奇葩面试题】因为太难而被禁用的17道Google面试题
  7. css3中的多列布局columns详解
  8. 反思PHP多个字符串函数
  9. 耳机不分主从是什么意思_“在网吧上网给玩家配置这样的耳机,是什么意思?”哈哈哈...
  10. mysql新建库和用户linux_Linux环境 Mysql新建用户和数据库并授权