朱文昊 Albert Zhu
朱文昊的中文博客--专注技术,向往自由
朱文昊的中文博客--专注技术,向往自由
2010年06月12日
作者:宋宝华 来源:天极网
朱文昊按语: 最近读到的一篇文章,收藏并作为一篇程序员修炼之路专辑中的一篇文章.
模块划分
模块划分的”划”是规划的意思,意指怎样合理的将一个很大的软件划分为一系列功能独立的部分合作完成系统的需求。C语言作为一种结构化的程序设计语言,在模块的划分上主要依据功能(依功能进行划分在面向对象设计中成为一个错误,牛顿定律遇到了相对论),C语言模块化程序设计需理解如下概念:
(1) 模块即是一个.c文件和一个.h文件的结合,头文件(.h)中是对于该模块接口的声明;
(2) 某模块提供给其它模块调用的外部函数及数据需在.h中文件中冠以extern关键字声明;
(3) 模块内的函数和全局变量需在.c文件开头冠以static关键字声明;
(4) 永远不要在.h文件中定义变量!定义变量和声明变量的区别在于定义会产生内存分配的操作,是汇编阶段的概念;而声明则只是告诉包含该声明的模块在连接阶段从其它模块寻找外部函数和变量。如:
| /*module1.h*/ int a = 5; /* 在模块1的.h文件中定义int a */ /*module1 .c*/ /*module2 .c*/ /*module3 .c*/ |
以上程序的结果是在模块1、2、3中都定义了整型变量a,a在不同的模块中对应不同的地址单元,这个世界上从来不需要这样的程序。正确的做法是:
| /*module1.h*/ extern int a; /* 在模块1的.h文件中声明int a */ /*module1 .c*/ /*module2 .c*/ /*module3 .c*/ |
这样如果模块1、2、3操作a的话,对应的是同一片内存单元。
一个嵌入式系统通常包括两类模块:
(1)硬件驱动模块,一种特定硬件对应一个模块;
(2)软件功能模块,其模块的划分应满足低偶合、高内聚的要求。
多任务还是单任务
所谓”单任务系统”是指该系统不能支持多任务并发操作,宏观串行地执行一个任务。而多任务系统则可以宏观并行(微观上可能串行)地”同时”执行多个任务。
多任务的并发执行通常依赖于一个多任务操作系统(OS),多任务OS的核心是系统调度器,它使用任务控制块(TCB)来管理任务调度功能。TCB包括任务的当前状态、优先级、要等待的事件或资源、任务程序码的起始地址、初始堆栈指针等信息。调度器在任务被激活时,要用到这些信息。此外,TCB还被用来存放任务的”上下文”(context)。任务的上下文就是当一个执行中的任务被停止时,所要保存的所有信息。通常,上下文就是计算机当前的状态,也即各个寄存器的内容。当发生任务切换时,当前运行的任务的上下文被存入TCB,并将要被执行的任务的上下文从它的TCB中取出,放入各个寄存器中。
嵌入式多任务OS的典型例子有Vxworks、ucLinux等。嵌入式OS并非遥不可及的神坛之物,我们可以用不到1000行代码实现一个针对80186处理器的功能最简单的OS内核,作者正准备进行此项工作,希望能将心得贡献给大家。
究竟选择多任务还是单任务方式,依赖于软件的体系是否庞大。例如,绝大多数手机程序都是多任务的,但也有一些小灵通的协议栈是单任务的,没有操作系统,它们的主程序轮流调用各个软件模块的处理程序,模拟多任务环境。
2010年06月11日
GPS可以作为探测运动和观测变化世界的绝佳工具。
如果用GPS接收器对某一固定点连续读取数据的话,就可以追踪这一点的运动情况,例如火山在内部岩浆作用下的不断膨胀,或是从南极大陆架上断裂下来的冰山的移动情况。增加接收器的数量(提高精度),用已知精确位置的GPS固定基站的信号作为基准,就可以清晰地捕捉到物体1/10英寸的突然运动,并对其进行实时监测。有了这项技术,科学家们就可以“上天入地”,探索很多我们原来并不十分清楚的动态过程。
香港的青马大桥是世界上最长的悬索桥,全长2200米,主桥跨度达1377米,两座吊塔高206米,距离海面62米。大桥可以承受强烈台风的袭击,桥体摇动距离可以达到几英尺,而疾驰而过的列车也会造成大桥主跨产生上下半米左右的振动。不过大桥的摇动也不能过于剧烈,如果桥身侧摆超过5米,大桥的钢梁和吊索就会像面条一样发生扭曲和弯折。
为了防患于未然,监测青马大桥的工程技术人员采用了GPS传感器阵列来对大桥的三维空间位置进行实时监控。他们在大桥的吊索、桥面和桥塔上安装了14个GPS接收器,这些接收器用长达数公里的光缆相连。这些传感器每秒钟都会向中央主控计算机发送10次各自的空间位置信息。同时在另外两个固定点上安装的GPS传感器也向主控计算机发回数据,主控计算机对数据进行校正以减小其误差。这样就可以把大桥的空间位置精确地显示出来,其水平误差不超过1厘米,垂直误差不超过2厘米。计算机还可以计算出风速和风向,并估算出大桥各个部位的应力和载荷状况,这样维护人员就可以方便地安排修理和维护工作。
科学家们还从来没有实地观察过金星或其他星球上的火山爆发。他们只知道在远古时代那里曾经有过火山爆发,但是对岩浆的流动速度、粘稠度等许多具体情况却无从得知。现在也没有能够在金星表面进行实地勘测的设备。于是科学家们就只能寻找地球上与之相类似的物质进行替代研究,然后把地球表面的物质与卫星照片进行对照,再分析其它星球的卫星照片,以此来分析推断遥远星球的情况。
在观察地球卫星照片的时候,科学家们发现美国新墨西哥州两处长达40到50公里的岩浆流,地理学家给它们起名为Car-rizozo和McCartys。这么长的岩浆流在地球上实属罕见,但在金星上却是很典型的情况。金星上的温度要比地球高得多,岩浆流的长度和存留时间要比地球上更长。
研究人员搜集了有关这两处岩浆流的几千份GPS数据,建立了岩浆流在许多不同地点的精确地形剖面图资料。这些岩浆流经地段的高度、坡度等地形资料能够帮助地质学家们了解岩浆的粘稠度,从而也就能判断出岩浆的成份及其流动的速度。Carrizozo和McCartys这两处岩浆流中间部分的粘稠度较低,而边缘部分粘稠度则较大,所以这两处岩浆流的特点就是中间流速大、不易冷却,边缘流速慢、冷却速度快。GPS数据还显示了凝固的岩浆外壳下隐藏着的奇异现象,其中包括岩浆流中心的一条岩浆管道,这一管道可以使岩浆在长达15公里的距离内保持融化状态。研究人员目前还不知道金星上是否也存在这种岩浆管道,这是一项很吸引人的研究内容。如果没有GPS的高精度测量技术,研究人员或许根本不会去研究这个问题,了解这一切的唯一途径就是亲自深入险地进行观测,但即使研究人员呆在火山爆发的地方亲自观察也未必能有这样的发现。
GPS系统在很多领域都获得了广泛的应用,它的功能现在已经不仅仅局限于为个人提供位置和时间信息了。拥有这项技术,我们向宇宙的真相又迈进了一步。GPS系统的未来无可限量,技术进步带来的梦想也是没有止境的。
2010年05月29日
腾讯微博的邀请码 蒲公英种子。有人用过了的话,请评论一下,好让别人知道哪个链接已经失效了。谢谢。(失效的已删除。每日检查)
5月31日最近更新获得的QQ腾讯微博的邀请码:
http://t.qq.com/invite/1e73af0e573436d07833
http://t.qq.com/invite/6e107876a0cb9e168675
http://t.qq.com/invite/d981e8af49eb0df5624d
http://t.qq.com/invite/07be4078012495c2799d
http://t.qq.com/invite/9a5beda996feb78771a5
29日有5个新的:
http://t.qq.com/invite/8870b1e184f1eb5144b7
http://t.qq.com/invite/55eaff62b78e9e077719
2010年05月25日
假如生活欺骗了你,
不要悲伤,不要忧郁;
阴霾的日子需要镇静
相信吧,那快乐的时光即将来临。
心儿永远憧憬着未来,
而现在却总是令人伤怀;
一切都是瞬息,一切都会过去,
而那过去了的,将会变成美好的回忆。
更多 >
2010年05月15日
当用户打开PC的电源,BIOS开机自检,按BIOS中设置的启动设备(通常是硬盘)启动,接着启动设备上安装的引导程序lilo或grub开始引导Linux,Linux首先进行内核的引导,接下来执行init程序,init程序调用了rc.sysinit和rc等程序,rc.sysinit和rc当完成系统初始化和运行服务的任务后,返回init;init启动了mingetty后,打开了终端供用户登录系统,用户登录成功后进入了Shell,这样就完成了从开机到登录的整个启动过程。
下面就将逐一介绍其中几个关键的部分:
第一部分:内核的引导(核内引导)
Red Hat9.0可以使用lilo或grub等引导程序开始引导Linux系统,当引导程序成功完成引导任务后,Linux从它们手中接管了CPU的控制权,然后CPU就开始执行Linux的核心映象代码,开始了Linux启动过程。这里使用了几个汇编程序来引导Linux,这一步泛及到Linux源代码树中的“arch/i386/boot”下的这几个文件:bootsect.S、setup.S、video.S等。
其中bootsect.S是生成引导扇区的汇编源码,它完成加载动作后直接跳转到setup.S的程序入口。setup.S的主要功能就是将系统参数(包括内存、磁盘等,由BIOS返回)拷贝到特别内存中,以便以后这些参数被保护模式下的代码来读取。此外,setup.S还将video.S中的代码包含进来,检测和设置显示器和显示模式。最后,setup.S将系统转换到保护模式,并跳转到 0×100000。
那么0×100000这个内存地址中存放的是什么代码?而这些代码又是从何而来的呢?
0×100000这个内存地址存放的是解压后的内核,因为Red Hat提供的内核包含了众多驱动和功能而显得比较大,所以在内核编译中使用了“makebzImage”方式,从而生成压缩过的内核,在RedHat中内核常常被命名为vmlinuz,在Linux的最初引导过程中,是通过”arch/i386/boot/compressed/”中的head.S利用misc.c中定义的decompress_kernel()函数,将内核vmlinuz解压到0×100000的。
当CPU跳到0×100000时,将执行”arch/i386/kernel/head.S”中的startup_32,它也是vmlinux的入口,然后就跳转到start_kernel()中去了。start_kernel()是”init/main.c”中的定义的函数,start_kernel()中调用了一系列初始化函数,以完成kernel本身的设置。start_kernel()函数中,做了大量的工作来建立基本的Linux核心环境。如果顺利执行完start_kernel(),则基本的Linux核心环境已经建立起来了。
在start_kernel()的最后,通过调用init()函数,系统创建第一个核心线程,启动了init过程。而核心线程init()主要是来进行一些外设初始化的工作的,包括调用do_basic_setup()完成外设及其驱动程序的加载和初始化。并完成文件系统初始化和root文件系统的安装。
当do_basic_setup()函数返回init(),init()又打开了/dev/console设备,重定向三个标准的输入输出文件stdin、stdout和stderr到控制台,最后,搜索文件系统中的init程序(或者由init=命令行参数指定的程序),并使用 execve()系统调用加载执行init程序。到此init()函数结束,内核的引导部分也到此结束了.