【转载】uCOS系统的思考

一:  世界潮流,浩浩汤汤,顺之者昌,逆之者亡---孙中山

从80X86到ARM9,再从ARM9到ARM7,平台是越做越简单,但是简单并不是意味着退步,反而是种潮流趋势。。。

在CISC道路上渐行渐远的INTEL,在移动市场无所作为,而且服务器市场也面临着ARM的潜在威胁。

废话不多说,还是直入主题:

CISC:复杂指令集

局限:CISC早期的计算机部件比较昂贵,主频低,运算速度慢。目的:为了提高运算速度,行动:人们不得不将越来越多的复杂指令加入到指令系统中,以提高计算机的处理效率,这就逐步形成复杂指令集计算机体系。为了在有限的指令长度内实现更多的指令,人们又设计了操作码扩展。然后,为了达到操作码扩展的先决条件——减少地址码,设计师又发现了各种寻址方式,如基址寻址、相对寻址等,以最大限度地压缩地址长度,为操作码留出空间。Intel公司的X86系列CPU是典型的CISC体系的结构,从最初的8086到后来的Pentium系列,每出一代新的CPU,都会有自己新的指令,而为了兼容以前的CPU平台上的软件,旧的CPU的指令集又必须保留,这就使指令的解码系统越来越复杂。CISC可以有效地减少编译代码中指令的数目,使取指操作所需要的内存访问数量达到最小化。此外CISC可以简化编译器结构,它在处理器指令集中包含了类似于程序设计语言结构的复杂指令,这些复杂指令减少了程序设计语言和机器语言之间的语义差别,而且简化了编译器的结构。

问题:控制字的数量及时钟周期的数目对于每一条指令都可以是不同的。因此在CISC中很难实现指令流水操作。另外,速度相对较慢的微程序存储器需要一个较长的时钟周期。由于指令流水和短的时钟周期都是快速执行程序的必要条件,因此CISC体系结构对于高效处理器而言不太合适的。

科普操作码:一条指令就是机器语言的一个语句,它是一组有意义的二进制代码,指令的基本格式如:操作码字段+地址码字段,其中操作码指明了指令的操作性质及功能,地址码则给出了操作数或操作数的地址。

ARM7的特性:

1:

采用RISC架构的MCU最显而易见的优点就是:

统一寻址模式,访问外设就像访问内存一样简单。而X86上则需要用特殊的IO操作指令来访问外设。

2:

差强人意的保护机制:

ARM7只提供了2中权限:

Handler Mode

Thread Mode:特权级/非特权级

一般来说,OS的代码使用特权级,APP代码使用非特权级,虽然可以保护OS代码不受非法访问。

但是没有MMU单元,APP的代码访问空间则得不到限制,线程之间可能互相破坏。所以你再也遇不到segment fault了。。转而是顷刻之间系统崩溃。。。。

事情正在起变化----毛泽dong

我通读过Linux Kernel的大部分源代码,特别是关于进程调度、内存管理这部分。以为掌握了现代操作系统的设计的精髓。。。面对麻雀般的uCOS2,难免有些轻视。。。

事情并非如此简单,原因是UCOS2的进程调度策略与现代的OS有很大的区别。

时间片轮转算法:

uCOS2的调度策略并没有采用这个算法,我想大概与uCOS2是一个实时系统有关。

如果高优先级的进程不主动释放CPU,那么低优先级的进程永远也得不到运行。

Linux实现了时间片轮转,只是高优先级的进程时间片长,优先运行。好处显而易见,高优先级的如果跑飞不会导致整个系统宕掉。

char类型引发的血案:

一个BUG。。。最后查了好久才发现是char类型的问题。

因为keil编译器char类型默认被解释为unsigned char [0-255]

而GCC/VC编译器char类型默认被解释为signed char [-128, 127]

由于出现了这种代码

char a;

while(a-- >=0)

{ ....}

所以程序就再也不会退出了。。。之所以查了好久,是我理所当然的认为char会被默认解释为signed char...

之后我翻阅了C99 Doc。。。。在没有加前缀的情况下,char的具体类型由编译器决定。。。

有时麻烦的加上一些看似不必要的东西,这些看似愚蠢的东西却能够在未来起到一些显著的作用

从LINUX&GCC转入UCOS2&KEIL,一切都变了。。看来我得重新审视一下这个小系统了。

uCOS2:

uCOS2唯一值得学习的一个地方就是关于进程调度的O(1)算法:

最简单也是最愚蠢的方法是维护一个链表List。

这种方法的问题是:当一个Thread就绪时,如果根据其优先级插入List,则算法的时间复杂度为O(n)。

Linux采用了Bitmap,uCOS2也不例外。当然uCOS2的处理更简单,因为uCOS2必须在系统编译时配置好支持的Thread最大数量,用来分配Bitmap。

例如:

支持64, 则分配8字节的Bitmap,如果支持256,则分配32字节的Bitmap。

Bitmap的每一个Bit代表thread的状态,如果Bit为1则表示就绪,0则表示挂起。

以64为例:

在Bitmap中如何快速找到为1的BIT,再转换成THREAD的优先级?

如果采用扫描的方式,按位与操作不是好方法,这里涉及循环和计数。所以操作时间和THREAD数量又成O(N)了。

所以uCOS2采用了分组的方法:8个字节64BIT,分为8*8,如图。

用OSRdyGrp变量的BIT来指示哪个分组里有就绪的THREAD,然后在提取出来该分组,再从该分组中找到优先级最高的THREAD。

线程优先级Priority和分组的关系如图。也就是X,Y如何组成Priority。

  还有一个问题:如何找到优先级最高的线程?Priority值越小,Thread优先级越高。

  比如OSRdyGrp = 0x10001000,OSRdyTbl[3]=0x10001000.

很明显OSRdyGrp的BIT3和OSRdyTbl[3]的BIT3代表的Thread 27才是我们想要的。

  为了解决这个问题,uCOS2又采用的了一个快速转换表OSMapTbl。

该转换表原理如下: 0x10001000 --->转换表---->3

0x00001000 --->转换表--->3

1字节8BIT,有256种BIT组合,但是组合方式返回的值是可以提前算好,存在OSMapTbl中。

比如OSRdyGrp=0x11111111和OSRdyGrp=0x00000001都应该返回0. [0代表第一个分组]

所以OSMapTbl如下:

INT8U const OSUnMapTbl[256] = {
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x00 to 0x0F */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x10 to 0x1F */
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x20 to 0x2F */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x30 to 0x3F */
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x40 to 0x4F */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x50 to 0x5F */
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x60 to 0x6F */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x70 to 0x7F */
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x80 to 0x8F */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x90 to 0x9F */
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xA0 to 0xAF */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xB0 to 0xBF */
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xC0 to 0xCF */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xD0 to 0xDF */
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xE0 to 0xEF */
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 0xF0 to 0xFF */
};  可以看出OSMapTbl[0]和OSMapTbl[255]都是0。

不说还没注意这个bitmap呢

Jean J. Labrosse,uCOS的作者,一个不懂哲学的人?

uCOS诞生于1992年,我想想,那个时候Linus在芬兰已经设计出了Linux的第一版本Beta0.12。David Cluter在西雅图为MicrioSoft第一个现代的版本操作系统内核NT忙的焦头烂额。

上个世纪90年代,OS设计已经进入了工业界,在学术界早已盖棺论定.

Labrosse在设计uCOS竟然没有采用最基本C/S模型。这也是设计OS的最基本哲学之一。

也就是Kernel为Server,App Thread为client。

App Thread 通过Kernel 提供的系统调用发出请求,具体操作由Kernel完成。

以X86平台为例,在Linux/Windows上,比如打开文件的Open函数,在libc库中的实现一定类似于:

MOV  AX, XX

MOV  BX, XX

MOV  CX, XX

MOV  DX, XX

INT 0X80

这里并不涉及文件操作的任何代码,而是APP向OS发出一个请求:我要打开FILE,请帮我打开。

1. BX、CX、DX用来保存Open的参数(FILE的路径,打开模式).

2. AX用来保存系统调用号,因为有很多系统调用,比如OPEN /WRITE/READ/CLOSE,他们各自对应一个调用号,比如OPEN对应1,WRITE对应2等等。。。

3. INT指令用来产生软中断。

软中断处理函数(exception handler),通过AX换算得到打开FILE操作的真正地址去执行。

这样的好处是:

任何线程不能直接控制硬件资源,只能提交请求,这样最大保证了系统的稳定性。

当然这个和CPU有莫大的关系,如果CPU没有提供类似于INT的软中断触发指令,和相应的保护模式,则不能实现现代OS。

作者可能受制于MOTO的芯片,才设计一个不符合惯例的OS.

OS Kernel / interrupt routine / app 采用一样的特权级。app任何微小的错误将导致整个系统崩溃。。。。

怪不得有朋友说,这类似于古老的DOS。。。

贡献两个技巧:

1 如何检验栈的使用量:

其实非常简单的操作,每次线程创建时,把栈空间全部清零。然后定期检测栈中非零的空间,就知道栈的使用量了。【只有线程运行到一定程度时,线程栈使用量才准确】

2 如何判断栈是否溢出:

在uCOS中创建任务时,在任务控制块中保存堆栈的栈底地址,并在栈底地址所对应的内存块中写入MAGIC NUMBER,  定期检查该字节是否被更改,用此来判断堆栈是否溢出。

本文链接:http://www.cnblogs.com/cposture/p/4291530.html

时间: 2024-10-24 12:44:54

【转载】uCOS系统的思考的相关文章

ucos系统初始化及启动过程

之前在ucos多任务切换中漏掉了一个变量, OSCtxSwCtr标识系统任务切换次数 主要应该还是用在调试功能中 Ucos系统初始化函数为OSInit(),主要完成以下功能 全局变量初始化 就绪任务表初始化 空任务控制块初始化 事件控制块链表初始化 信号量集初始化 存储器管理初始化 Qs队列控制初始化 系统空闲任务初始化 系统统计任务初始化 部分功能需要依靠宏定义打开另外要注意一个变量OSTaskCtr标识系统全部任务数,在初始化完成之后就可以创建任务了,创建任务完成之后启动系统使用OSStar

关于笔记系统的思考

关于笔记系统的思考 本文中所讲述的笔记系统面向于重度笔记患者,我们不立志于在自己的笔记库中新建一个百科全书,笔记的目的在于周期性的系统沉淀和归纳自己的所得,其重点在于如何将已掌握的知识按照自己的思路(思维方式)来进行归纳和串联(思维的文字化). 个人所接触到的笔记类产品围绕evernote展开.个人是evernote的重度用户,四年多的重度笔记使用,总体总结如下: 收集完了就不再使用的笔记没有任何作用 电子笔记不如实际纸质笔记本的地方在于对于已有的量的感知和回顾,如果你不记得你在电子笔记里面记录

[转载]window系统下TCP参数优化

注:此文转载自红黑联盟,最近服务器遇到周期性down掉的问题,拖了两三周请教了前辈之后才知道无关应用和数据库的事情,是tcp设置的问题.从网上找个这篇文章,解释的很不错.有兴趣请至红黑联盟翻阅原文. TCP连接的状态与关闭方式及其对Server与Client的影响 http://www.2cto.com/net/201304/206071.html 通常会采用修改注册表的方式改进Windows的系统参数.下面将为大家介绍Windows系统下的TCP参数优化方式,适用于Windows 2003.W

虚拟机做服务器实现无人值守安装系统的思考和问题

这个问题我研究很久,目前的情况是这样的,让我慢慢道来. 一.整体拓扑 1.笔记本电脑宿主主机(xp系统),宿主主机上安装一个vm10的虚拟机. 2.虚拟机安装redhat6.0的linux系统,作为DHCP服务器.TFTP服务器.NFS服务器/HTTP服务器/FTP服务器的整体服务器. 3.客户机是另外一台没有任何系统的带有PXE功能的电脑,并且BIOS已经配置成为网卡启动. 4.是我简单画了一个图片,以便理解. 二.思考和问题 本人在一个独立的服务器上部署这些相关的服务器,可以顺利完成无人值守

秒杀系统的思考方式与设计思路--左手隔离,右手分层

大家好,我是崔皓. 很高兴有这样一个机会和大家认识.我在IT行业从事软件开发工作十余年了,足迹涵盖企业服务,互联网,企业数字化转型等.工作之余热爱阅读和学习,希望能通过这个专栏和大家成为朋友. 开篇 本次专栏要给大家分享的是"如何设计秒杀系统",专栏共包括15章,本章是第一章.今天会给大家介绍以下内容: 秒杀场景的特征 隔离的设计思路 分层设计思路本章的讲解思路是,提出秒杀场景的特征,也就是理解什么是秒杀.然后介绍在秒杀系统设计的底线,有了底线才能保证进可攻退可守.最后介绍使用哪些方法

转载CI系统搭建二、Gitlab的安装和配置

博客转载于longgeek.com, 地址 http://longgeek.com/2013/12/26/ci-system-structures-ii-gitlab-installation/#i-4. 我在自己电脑上安装了这个gitLab,亲自测试过博客中描述的步骤很全.其中 域名如果没有替换为自己本地的地址,需要带上端口号.其中端口号为8081 上一篇文章 CI 系统搭建:一. 基础环境设置.规划 大概规划了下环境,本文主要用来记录安装 Gitlab 的过程,主要参考官方文档 并没有做太多

图片系统架构思考之一:删除图片--不容忽视

对于一个网站系统,图片的处理往往是一个不可或缺的事情,不管是淘宝还是京东,每天都有大量的产品上架.下架,其中就涉及到了大量图片的管理.比如很简单的一个产品表,里面有:产品ID.产品名称.产品图片 字段,此时应该怎么保存产品图片呢? 一种方式是将图片保存到数据库里面,采用blob类型的字段,此时该字段的内容就是图片的二进制表示:另外一种方式是将图片保存到普通的文件系统上,比如windows或者linux的分区上,在数据库的相应字段中保存的是该图片文件的路径信息,该模式的一个简单示意图如下:当客户端

机房收费系统--设计模式思考

今天与阿真同学简略讨论了一下外观模式和抽象工厂+反射+配置文件在机房重构中的应用,引发了几个简单的思考,现与君共勉: 1. B层为什么觉得按照数据库表来划分比较合理? 思考再三:B层方法是实现对数据表的增删改查进行逻辑操作,而且还要考虑解耦效果(我是这么理解耦合的,如果一个类中只放一个方法,一旦出错,它只影响自己,耦合度就低:如果有十个方法,一个方法出错,该类的实例化就会出错,这样耦合程度就越强),所以B层的类中放的方法不应太多:考虑到每个窗体大部分都是对一张表进行的操作,这样,将每张表对应的增

[转载] 可伸缩系统的架构经验

原文: http://agiledon.github.io/blog/2013/02/27/scalability-system-architecture-lessons/ 最近,阅读了Will Larson的文章Introduction to Architecting System for Scale,感觉很有价值.作者分享了他在Yahoo!与Digg收获的设计可伸缩系统的架构经验.在我过往的架构经验中,由于主要参与开发企业软件系统,这种面向企业内部的软件系统通常不会有太大的负载量,太多的并发