凡东 さんのプロフィール凡东的共享空间フォトブログつながり ツール ヘルプ

ブログ


10月21日

Java中的观察者模式(Observer)

观察者模式理解为就是一个对象发生某种变化时,它的观察者做出相应的动作。观察者和被观察的对象之前建立关系。
 
Java作为一种面向对象的开发语言,对实现设计模式提供了良好的支持,并且提供了许多默认的实现,比如:通过Java中的Observable类和Observer接口可以方便的实现观察者模式。

下面我们就用一个实际的例子来说明:日常生活中说起观察者,最常见的例子可能就是天气预报,在这里我们的观察对象是地球,而我们是通过发射气象卫星这个观察者来检测地球气象变化的。

所以这个例子中涉及三个对象:
地球  (Earth):                                          被观察对象
气象卫星(Satellite):                        观察者
气象局(WeatherService):        客户端调用

被观察对象:地球  (Earth)


 import    java.util.Observable;

 /**  */  /**  
 *  被观察对象:地球
 *  
 *    @author    zjun
 *    @version    1.0  create  on  2006-5-18  9:42:45
   */  
   public      class    Earth    extends    Observable      {
         private    String  weather    =      "  晴朗  "  ;

         /**  */  /**  
         *    @return    Returns  the  weather.
           */  
           public    String  getWeather()      {
                 return    weather;
       }  
 
           /**  */  /**  
         *    @param    weather
         *                        The  weather  to  set.
           */  
           public      void    setWeather(String  weather)      {
                 this  .weather    =    weather;
                 //    设置变化点  
                 setChanged();
               notifyObservers(weather);
       }  
}  
[注意]  在需检测的对象前需要设置变化点setChanged()和通知观察者notifyObservers(),这两个函数是由Observable类实现的,封装了观察者模式实现的细节。

观察者:气象卫星(Satellite)  

 import    java.util.Observable;
 import    java.util.Observer;

 /**  */  /**  
 *  观察对象:气象卫星
 *  
 *    @author    zjun
 *    @version    1.0  create  on  2006-5-18  9:46:30
   */  
   public      class    Satellite    implements    Observer      {
         private    String  weather;

         public      void    update(Observable  obj,  Object  arg)      {
               weather    =    (String)  arg;
                 //    捕获天气变化情况,反馈给检测者  
                 System.out.println(  "  近期天气变化:  "      +    weather);
       }  
}  
客户端调用:气象局(WeatherService)  

   /**  */  /**  
 *  客户端调用:天气预报
 *  
 *    @author    zjun
 *    @version    1.0  create  on  2006-5-18  9:57:19
   */  
   public      class    WeatherService      {

         /**  */  /**  
         *    @param    args
           */  
           public      static      void    main(String[]  args)      {
               Earth  earth    =      new    Earth();
               
               Satellite  satellite    =      new    Satellite();
                 //    发射气象卫星  
                 earth.addObserver(satellite);

               System.out.println(  "  天气预报:  "  );
               System.out.println(  "  ------------  "  );
               earth.setWeather(  "  台风‘珍珠’逼近  "  );
               earth.setWeather(  "  大到暴雨  "  );
               earth.setWeather(  "  天气炎热  "  );
       }  
}  
 
[运行结果]  

 天气预报:
------------
近期天气变化:台风‘珍珠’逼近
近期天气变化:大到暴雨
近期天气变化:天气炎热
10月20日

使用Ubuntu搭建Web服务器(PHP)

 

http://www.linuxidc.com/Linux/2008-07/14178p2.htm(zhuanzai)

Apache 是一种功能强大的Web服务器。如今,Internet上无数运行在Linux上的Apache服务器正为Web世界的日益繁荣提供着有力的支撑。本文将向读者介绍如何在Ubuntu Linux系统迅速搭建Apache Web服务器。

  尽管Ubuntu 是一种新兴的Linux分支,但Ubuntu 组织却为Apache提供了丰富的支持软件,这些软件都可以从发行版的光盘获取,也可以从官方站点轻松下载。所以,Ubuntu非常适合作为Web服务器的平台。

一、 安装Apache

  下面,我们首先介绍如何安装Apache。具体安装命令如下所示:

  $ sudo apt-get install apache2

  然后运行Apache,命令如下所示:

  $ sudo /etc/init.d/apache2 restart

  Apache在安装期间将会新建一个目录:/var/www,该目录是该服务器中存放文档的根目录。只要在浏览器的地址栏输入 http://localhost/ 或机器的IP地址就能访问放置在此目录中的所有文档。

  二、 安装PHP

  PHP是一种流行的服务器端脚本语言,一般与MySQL或 Postgres结合起来用于管理Web内容、blog和论坛。下面介绍其安装方法,其实它的安装也很简单,命令如下所示:

  $ sudo apt-get install libapache2-mod-php5

  重新启动 Apache 以加载上面安装的模块:

  $ sudo /etc/init.d/apache2 restart

  为了验证PHP模块是否正确加载,我们可以建立一个PHP文件,然后尝试通过Web服务器访问该文件。此外,我们知道PHP内建了一个phpinfo函数,该函数能够给出它的环境的详细信息。所以我们还可以利用下面的命令来检查PHP的工作情况:

  sudo sh -c "echo '' > /var/www/info.php"

  之后,在浏览器地址栏键入http://localhost/info.php,然后回车,这时应该能看到一个颜面,给出刚才安装的PHP的详细信息。需要注意的是,如果在此过程中浏览器不显示页面,而是提示你下载文件,这就说明 Apache没有正确加载PHP模块。解决问题的办法是,在/etc/apache2/apache2.conf 或 /etc/apache2/mods-enabled/php5.conf文件中加入下面一行命令:

  AddType application/x-httpd-php .php .phtml .php3

  加入上面的命令行后,为了保证Apache重新读取配置文件关闭,我们可以通过下面的命令将其关闭,然后再加以启动:

  $ sudo /etc/init.d/apache2 stop

  $ sudo /etc/init.d/apache2 start

三、配置动态虚拟主机

  一般情况下,我们会在Web服务器上寄放多个Web站点,并且每个站点都有它自己的虚拟服务器。对于Apache来说,它同时支持基于名称的虚拟服务器和基于IP的服务器。

  对于基于IP的虚拟服务器,每个站点都具有一个单独的IP地址,这样的缺点是使用太多的IP地址,但如今IPv4的地址已有枯竭的迹象,所以不提倡使用,通常在要求使用SSL 时才使用。

对于基于名称的虚拟服务器,多个Web站点共享一个IP地址。在这种情况下,通常根据HTTP请求头部来决定将其发给哪一个站点。为此,我们需要为每个虚拟服务器分别建立一个配置,给作为Web站点的根的目录以及主机命名。但是,如果这样的话我们每当添加一个新的虚拟服务器时,就要修改 Apache的配置并重新启动,这的确很烦人呢!

  值得高兴的是,如果使用动态虚拟主机技术的话,可以随时加入虚拟主机时而不必重新配置或启动Apache。该技术要用到一个模块,称为vhost_alias。我们可以通过在Apache2已启用的模块目录中建立一个符号链接来启用该模块,命令如下所示:

  $ sudo ln -s /etc/apache2/mods-available/vhost_alias.load

  /etc/apache2/mods-enabled/vhost_alias.load

  要想使vhost_alias正常工作,我们还需要修改/etc/apache2/apache2.conf 来关闭常规名称(canonical names),修改日志文件的配置,并为我们的虚拟主机规定存放位置。下面是一个实例:

  #从"Host:"头中取得主机名

  UseCanonicalName Off

  # 这种日志格式可以从第一个字段中提取出主机名

  LogFormat "%V %h %l %u %t "%r" %s %b" vcommon

  CustomLog /var/log/apache2/access_log vcommon

  # 在返回请求的文件名路径中包含主机名

  VirtualDocumentRoot /var/www/vhosts/%0/web

  VirtualScriptAlias /var/www/vhosts/%0/cgi-bin

  接下来,创建存放虚拟主机的目录,命令如下:

  $ sudo mkdir /var/www/vhosts

  新建一个基干虚拟服务器,命令如下所示:

  $ sudo mkdir -p /var/www/vhosts/skeleton/cgi-bin

  $ sudo cp -a /var/www/apache2-default /var/www/vhosts/skeleton/web

  重新启动apache2,使得上面的配置生效,方法如下所示:

  $ sudo /etc/init.d/apache2 restart

  好了,现在我们可以建立基于名称的虚拟主机了。方法是将基干拷贝到要响应的主机名。举例来说,要想为www.Linuxidc.com新建一个虚拟服务器的话,只要运行下面的命令就行了:

  $ sudo cp -a /var/www/vhosts/skeleton /var/www/vhosts/

  www. Linuxidc.com

  现在,所有到达你的Apache服务器的HTTP连接中,只要其“Host:”头部被设成 www. Linuxidc.com,那么将由对应的虚拟服务器来响应。

  为了早些看到我们的劳动成果,可以在本地进行测试。为此编辑/etc/hosts,加入下面一项:

  127.0.0.1 www. Linuxidc.com

  这样,在本机上就能访问该站点了。但是,为了让所有用户都能访问虚拟主机,还需申请域名,并且我们还需要在公共DNS服务器上进行设置。

web服务器

WEB服务器也称为WWW(WORLD WIDE WEB)服务器,主要功能是提供网上信息浏览服务。
Web服务器是指驻留于因特网上某种类型计算机的程序。当Web浏览器(客户端)连到服务器上并请求文件时,服务器将处理该请求并将文件发送到该浏览器上,附带的信息会告诉浏览器如何查看该文件(即文件类型)。服务器使用HTTP(超文本传输协议)进行信息交流,这就是人们常把它们称为HTTPD服务器的原因。
APACHE
   apache仍然是世界上用的最多的Web服务器,市场占有率达60%左右。它源于 NCSAhttpd服务器,当NCSA WWW服务器项目停止后,那些使用NCSA WWW服务器的人们开始交换用于此服务器的补丁,这也是apache名称的由来(pache 补丁)。世界上很多著名的网站都是Apache的产物,它的成功之处主要在于它的源代码开放、有一支开放的开发队伍、支持跨平台的应用(可以运行在几乎所有的Unix、Windows、Linux系统平台上)以及它的可移植性等方面。
  Tomcat
  Tomcat是一个开放源代码、运行servlet和JSP Web应用软件的基于Java的Web应用软件容器。Tomcat Server是根据servlet和JSP规范进行执行的,因此我们就可以说Tomcat Server也实行了Apache-Jakarta规范且比绝大多数商业应用软件服务器要好。
  Tomcat是Java Servlet 2.2和JavaServer Pages 1.1技术的标准实现,是基于Apache许可证下开发的自由软件。Tomcat是完全重写的Servlet API 2.2和JSP 1.1兼容的Servlet/JSP容器。Tomcat使用了JServ的一些代码,特别是Apache服务适配器。随着Catalina Servlet引擎的出现,Tomcat第四版号的性能得到提升,使得它成为一个值得考虑的Servlet/JSP容器,因此目前许多WEB服务器都是采用Tomcat。
 
10月18日

制作交叉编译链

 
 前段时间研究uboot的修改,只是关注了大概框架的修改,当时下载的uboot1.2.0,交叉编译链也是下载的现成的,cross-2.95.3,当时就是编译不过去。这种标准的文件没有进行修改过编译出问题很奇怪,在网上找到了一些信息,这个交叉编译链只支持到uboot1.1.4。于是又下载了uboot1.1.4,编译成功,很兴奋阿。
交叉工具链下载地址:
ftp://ftp.arm.linux.org.uk/pub/linux/arm/toolchain/
 后来在移植内核时发现高版本的内核中已经加入了对s3c2440的支持,所以决定采用高版本的内核2.6,同时uboot决定采用1.2.0。按照上次的思路下载了最新的cross-3.2,居然编译不了,连1.1.4都编译不了。这种情况只能归咎于版本问题。这种现成的交叉编译链有一定的局限性,比如它采用的gcc是哪个版本,
是否能编译我需要的内核和uboot? 交叉编译链是需要根据自己的情况制作的。 幸好有crosstool这个工具。省去了一步一步制作的麻烦。
 http://kegel.com/crosstool/
 下载crosstool-0.43.tar.gz,解压。
 我的linux为redhat 9。
 硬件平台为arm9,s3c2440
 首先下载制作交叉编译链所需的文件,地址:ftp.gnu.org
binutils-2.15.tar.bz2
gdb-6.5.tar.bz2
gcc-4.1.0.tar.bz2
gcc-3.3.6.tar.gz
glibc-linuxthreads-2.3.2.tar.gz
glibc-2.3.2.tar.gz
linux-libc-headers-2.6.12.0.tar.bz2
linux-2.6.10.tar.gz
将这些文件存放在$HOME的downloads目录下,不用解压。
进入crosstool-0.43目录中,执行cp demo-arm.sh arm.sh 复制一个模板进行修改。
执行vi arm.sh进行编辑
#!/bin/sh
# This script has one line for each known working toolchain
# for this architecture.           Uncomment the one you want.
# Generated by generate-demo.pl from buildlogs/all.dats.txt
set -ex
TARBALLS_DIR=$HOME/downloads  //制作交叉编译所需文件的存放位置!
RESULT_TOP=/opt/crosstool //生成的交叉编译链的存放地址,注意你是否对该文件有写权限
export TARBALLS_DIR RESULT_TOP
GCC_LANGUAGES="c,c++"      //生成的工具链支持的语言的种类!
export GCC_LANGUAGES
# Really, you should do the mkdir before running this,
# and chown /opt/crosstool to yourself so you don't need to run as root.
mkdir -p $RESULT_TOP
#eval `cat arm9tdmi.dat gcc-3.2.3-glibc-2.2.5.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-3.2.3-glibc-2.3.2.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-3.2.3-glibc-2.3.2-tls.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-3.3.6-glibc-2.2.5.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-3.3.6-glibc-2.3.2.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-3.3.6-glibc-2.3.2-tls.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.2.5.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.2.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.2-tls.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.5.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.5-tls.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.6.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-3.4.5-glibc-2.3.6-tls.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-4.0.2-glibc-2.3.2.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-4.0.2-glibc-2.3.2-tls.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-4.0.2-glibc-2.3.5.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-4.0.2-glibc-2.3.5-tls.dat` sh all.sh --notest   
#eval `cat arm9tdmi.dat gcc-4.0.2-glibc-2.3.6.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-4.0.2-glibc-2.3.6-tls.dat` sh all.sh --notest
#eval `cat arm9tdmi.dat gcc-4.1.0-glibc-2.3.2.dat` sh all.sh --notest
eval `cat arm9tdmi.dat gcc-4.1.0-glibc-2.3.2-tls.dat` sh all.sh --notest//这块根据需要我选择了高版本的gcc-4.1.0
echo Done. //上面表示你要选工具链的版本号!"#"起注释功能!我们可以选择一行!
打开crosstool-0.43目录下的arm.dat文件,内容如下:
KERNELCONFIG=`pwd`/arm.config
TARGET=arm-linux-gnu
TARGET_CFLAGS="-O"
这里TARGET=需要根据自己的情况修改一下,比如目前为arm-linux-gnu那么最终编译完成后我的gcc为
arm-linux-gnu-gcc。
 
打开crosstool-0.43目录下的gcc-4.1.0-glibc-2.3.2-tls.dat文件,内容如下:
BINUTILS_DIR=binutils-2.15
GCC_COR_DIR=gcc-3.3.6
GCC_DIR=gcc-4.1.0
GLIBC_DIR=glibc-2.3.2
LINUX_DIR=linux-2.6.10
LINUX_SANITIZED_HEADER_DIR=linux-libc-headers-2.6.12.0
GLIBCTHREADS_FILENAME=glibc-linuxthreads-2.3.2
GDB_DIR=gdb-6.5
GLIBC_EXTRA_CONFIG="$GLIBC_EXTRA_CONFIG --with-tls --with-__thread           --enable-kernel=2.4.18"
注意:这里边的几个版本的文件必须在$HOME/downloads文件夹下有。
到这里就设置完了。
到crosstool-0.43目录下执行./arm.sh经过大概1小时就OK了,然后设置环境变量。
PATH=/opt/crosstool/gcc-4.1.0-glibc-2.3.2/arm-linux-gnu/bin:$PATH
具体设置方法可参考linux应用中的环境变量及设置。
 
 
9月27日

nand flash nor flash (转载)

Nor和NAND的具体区别

NOR和NAND是现在市场上两种主要的非易失闪存技术。Intel于1988年首先开发出NOR 
flash技术,彻底改变了原先由EPROM和EEPROM一统
天下的局面。紧接着,1989年,东芝公司发表了NAND flash结构,强调降低每比特的成
本,更高的性能,并且象磁盘一样可以通过接口
轻松升级。但是经过了十多年之后,仍然有相当多的硬件工程师分不清NOR和NAND闪存。

  相“flash存储器”经常可以与相“NOR存储器”互换使用。许多业内人士也搞不清
楚NAND闪存技术相对于NOR技术的优越之处,因
为大多数情况下闪存只是用来存储少量的代码,这时NOR闪存更适合一些。而NAND则是高
数据存储密度的理想解决方案。 
  NOR的特点是芯片内执行(XIP, eXecute In Place),这样应用程序可以直接在flash
闪存内运行,不必再把代码读到系统RAM中。
NOR的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除
速度大大影响了它的性能。
  NAND结构能提供极高的单元密度,可以达到高存储密度,并且写入和擦除的速度也
很快。应用NAND的困难在于flash的管理和需要
特殊的系统接口。

性能比较
  flash闪存是非易失存储器,可以对称为块的存储器单元块进行擦写和再编程。任何
flash器件的写入操作只能在空或已擦除的单元
内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除。NAND器件执行擦除
操作是十分简单的,而NOR则要求在进行擦除前
先要将目标块内所有的位都写为0。
  由于擦除NOR器件时是以64~128KB的块进行的,执行一个写入/擦除操作的时间为5s
,与此相反,擦除NAND器件是以8~32KB的块进
行的,执行相同的操作最多只需要4ms。
  执行擦除时块尺寸的不同进一步拉大了NOR和NADN之间的性能差距,统计表明,对于
给定的一套写入操作(尤其是更新小文件时),
更多的擦除操作必须在基于NOR的单元中进行。这样,当选择存储解决方案时,设计师必
须权衡以下的各项因素。
  ● NOR的读速度比NAND稍快一些。
  ● NAND的写入速度比NOR快很多。
  ● NAND的4ms擦除速度远比NOR的5s快。
  ● 大多数写入操作需要先进行擦除操作。
  ● NAND的擦除单元更小,相应的擦除电路更少。

接口差别
  NOR flash带有SRAM接口,有足够的地址引脚来寻址,可以很容易地存取其内部的每
一个字节。
  NAND器件使用复杂的I/O口来串行地存取数据,各个产品或厂商的方法可能各不相同
。8个引脚用来传送控制、地址和数据信息。
  NAND读和写操作采用512字节的块,这一点有点像硬盘管理此类操作,很自然地,基
于NAND的存储器就可以取代硬盘或其他块设备。

容量和成本
  NAND flash的单元尺寸几乎是NOR器件的一半,由于生产过程更为简单,NAND结构可
以在给定的模具尺寸内提供更高的容量,也就
相应地降低了价格。
  NOR flash占据了容量为1~16MB闪存市场的大部分,而NAND flash只是用在8~128M
B的产品当中,这也说明NOR主要应用在代码存
储介质中,NAND适合于数据存储,NAND在CompactFlash、Secure Digital、PC Cards和M
MC存储卡市场上所占份额最大。

可靠性和耐用性
  采用flahs介质时一个需要重点考虑的问题是可靠性。对于需要扩展MTBF的系统来说
,Flash是非常合适的存储方案。可以从寿命
(耐用性)、位交换和坏块处理三个方面来比较NOR和NAND的可靠性。
  寿命(耐用性)
  在NAND闪存中每个块的最大擦写次数是一百万次,而NOR的擦写次数是十万次。NAND
存储器除了具有10比1的块擦除周期优势,典型
的NAND块尺寸要比NOR器件小8倍,每个NAND存储器块在给定的时间内的删除次数要少一
些。
  位交换
  所有flash器件都受位交换现象的困扰。在某些情况下(很少见,NAND发生的次数要
比NOR多),一个比特位会发生反转或被报告反转
了。
  一位的变化可能不很明显,但是如果发生在一个关键文件上,这个小小的故障可能
导致系统停机。如果只是报告有问题,多读几次
就可能解决了。
  当然,如果这个位真的改变了,就必须采用错误探测/错误更正(EDC/ECC)算法。位
反转的问题更多见于NAND闪存,NAND的供应商建
议使用NAND闪存的时候,同时使用EDC/ECC算法。
  这个问题对于用NAND存储多媒体信息时倒不是致命的。当然,如果用本地存储设备
来存储操作系统、配置文件或其他敏感信息时,
必须使用EDC/ECC系统以确保可靠性。
  坏块处理
  NAND器件中的坏块是随机分布的。以前也曾有过消除坏块的努力,但发现成品率太
低,代价太高,根本不划算。
  NAND器件需要对介质进行初始化扫描以发现坏块,并将坏块标记为不可用。在已制
成的器件中,如果通过可靠的方法不能进行这项
处理,将导致高故障率。 

易于使用
  可以非常直接地使用基于NOR的闪存,可以像其他存储器那样连接,并可以在上面直
接运行代码。
  由于需要I/O接口,NAND要复杂得多。各种NAND器件的存取方法因厂家而异。
  在使用NAND器件时,必须先写入驱动程序,才能继续执行其他操作。向NAND器件写
入信息需要相当的技巧,因为设计师绝不能向坏
块写入,这就意味着在NAND器件上自始至终都必须进行虚拟映射。

软件支持
  当讨论软件支持的时候,应该区别基本的读/写/擦操作和高一级的用于磁盘仿真和
闪存管理算法的软件,包括性能优化。
  在NOR器件上运行代码不需要任何的软件支持,在NAND器件上进行同样操作时,通常
需要驱动程序,也就是内存技术驱动程序(MTD
),NAND和NOR器件在进行写入和擦除操作时都需要MTD。
  使用NOR器件时所需要的MTD要相对少一些,许多厂商都提供用于NOR器件的更高级软
件,这其中包括M-System的TrueFFS驱动,该驱
动被Wind River System、Microsoft、QNX Software System、Symbian和Intel等厂商所
采用。
  驱动还用于对DiskOnChip产品进行仿真和NAND闪存的管理,包括纠错、坏块处理和
损耗平衡。

8月21日

Linux操作系统下硬盘挂载方法

新手学堂:Linux操作系统下硬盘挂载方法

挂载Windows分区

1. 手工挂载
在Linux中也可以读取Windows分区,包括fat32格式的和ntfs格式的。首先你得知道Linux下对硬盘分区的称呼。比如Windows下的C盘通常是hda1,D盘是hda5,E盘是hda6,等等。详细情形请看相关文档。

要挂载Windows分区,首先得确定你所用的Linux系统的locale(这个locale包括了系统使用的语言和字符的编码等信息)。中文 Linux 常用的locale是zh_CN.gb2312,zh_CN.gbk,zh_CN.gb18030 和 zh_CN.UTF-8 。

在默认安装中,Debian Linux和Mandriva Linux的locale是zh_CN.gb2312,而Ubuntu Linux和Fedora Linux的locale是zh_CN.UTF-8 。最好不要随便更改locale,否则会出现很多乱码的情形。要查看系统的locale,可以在终端下输入下面的命令查看:

echo $LANG

其次,你得知道你的windows分区的格式,这个在windows的分区的属性中可以看到,一般是fat32和ntfs格式的。

假设你的locale是zh_CN.UTF-8,要挂载一个/dev/hda1的fat32格式的windows分区到/mnt/C目录(若这个目录不存在手工新建一个),可以在终端下输入以下命令(在Ubuntu里还需要在这行命令前加上sudo):

mount -t vfat /dev/hda1 /mnt/C -o iocharset=utf8

如果你的locale不是zh_CN.UTF-8,把上面命令的utf8改为gb2312;如果这个windows分区是ntfs格式的,将上面命令的vfat改为ntfs。

这样挂载的ntfs格式的分区,只有root能读取,如果需要让普通用户也能读取,需要再加上umask=022选项,如下:
mount -t ntfs /dev/hda1 /mnt/C -o iocharset=utf8,umask=022

类似地,如果要让挂载的分区允许所有用户读取和修改,可以将上面的umask=022,改为umask=0就可以了。

卸载分区就简单多了:
umount /dev/hda1

有时候卸载分区时提示分区繁忙(device is busy),可以先用下面的命令看看哪个进程在使用此分区:
fuser -cu /dev/hda1

假如屏幕的输出为
/dev/hda1: 8463m(cck)

则可以用此命令看这个进程对应的程序名字:
ps 8463

然后可以用此命令结束此进程:
kill -9 8463

这样就可以正常卸载分区了。

 

A盘:       mount   /dev/fd0         /mnt/floppy  
  光盘:     mount   /dev/cdrom     /mnt/cdrom  
  C盘:       mount   /dev/hda1       /mnt/disk-c     (要提前建立/mnt/disk-c,下同)  
  D盘:       mount   /dev/hda5       /mnt/disk-d      
  E盘:       mount   /dev/hda6       /mnt/disk-e      
  U盘:       mount   /dev/sda1       /mnt/disk-u  

 



2. 自动挂载
要让Linux系统启动时自动挂载windows分区,可以把上述的命令写入 /etc/fstab 文件中,下面是一个例子:


# /etc/fstab: static file system information.##[file system] [mount point] [type] [options] [dump] [pass]proc /proc proc defaults 0 0/dev/hda9 / ext3 defaults 0 1/dev/hda13 none swap sw 0 0/dev/hdc /media/cdrom iso9660 ro,user,noauto 0 0/dev/fd0 /media/floppy auto rw,user,noauto 0 0/dev/hda10 /mnt/debian ext3 defaults 0 0/dev/hda1 /mnt/C ntfs utf8,umask=022 0 0/dev/hda5 /mnt/D vfat utf8,umask=0 0 0

 

 

 


原文链接:http://www.linuxeden.com/html/newbie/20080625/58957.html

7月18日

关于服务器 (转载)


在这个全民上网的时代,对于个人电脑的了解与使用,大多数的人都能够说出个大致,但是对于处于网络应用核心的服务器,大部分人的第一感觉还是比较神秘。那么到底什么是服务器呢?

  什么是服务器?

  从理论定义来看,服务器是网络环境中的高性能计算机,它侦听网络上其它计算机(客户机)提交的服务请求,并提供相应的服务。为此,服务器必须具有承担服务并且保障服务质量的能力。

  但是这样来解释仍然显得较为深奥模糊,其实服务器与个人电脑的功能相类似,均是帮助人类处理信息的工具,只是二者的定位不同,个人电脑(简称为 Personal Computer,PC)是为满足个人的多功能需要而设计的,而服务器是为满足众多用户同时在其上处理数据而设计的。而多人如何同时使用同一台服务器呢? 这只能通过网络互联,来帮助达到这一共同使用的目的。

  我们再来看服务器的功能,服务器可以用来搭建网页服务(我们平常上网所看到的网页页面的数据就是存储在服务器上供人访问的)、邮件服务(我们发 的所有电子邮件都需要经过服务器的处理、发送与接收)、文件共享&打印共享服务、数据库服务等。而这所有的应用都有一个共同的特点,他们面向的都 不是一个人,而是众多的人,同时处理的是众多的数据。所以服务器与网络是密不可分的,可以说离开了网络,就没有服务器;服务器是为提供服务而生,只有在网 络环境下它才有存在的价值。而个人电脑完全可以在单机的情况下完成主人的数据处理任务。

 

图1.网络应用中的服务器

  服务器的硬件构成:

  其实说起来服务器系统的硬件构成与我们平常所接触的电脑有众多的相似之处,主要的硬件构成仍然包含如下几个主要部分:中央处理器、内存、芯片组、I/O总线、I/O设备、电源、机箱和相关软件。这也成了我们选购一台服务器时所主要关注的指标。

  整个服务器系统就像一个人,处理器就是服务器的大脑,而各种总线就像是分布与全身肌肉中的神经,芯片组就像是脊髓,而I/O设备就像是通过神经系统支配的人的手、眼睛、耳朵和嘴;而电源系统就像是血液循环系统,它将能量输送到身体的所有地方。

图2.服务器硬件组成直观图
服务器的整体设计目标:

  对于一台服务器来讲,服务器的性能设计目标是如何平衡各部分的性能,使整个系统的性能达到最优。如果一台服务器有每秒处理1000个服务请求的能力,但网卡只能接受200个请求,而硬盘只能负担150个,而各种总线的负载能力仅能承担100个请求的话,那这台服务器得处理能力只能是100个请求/秒,有超过80%的处理器计算能力浪费了。

      所以设计一个好服务器的最终目的就是通过平衡各方面的性能,使得各部分配合得当,并能够充分发挥能力。我们可以从这几个方面来衡量服务器是否达到了其设计 目的:R:Reliability——可靠性;A:Availability——可用性;S:Scalability——可扩展性;U: Usability——易用性; M:Manageability——可管理性,即服务器的RASUM衡量标准。

  由于服务器在网络中提供服务,那么这个服务的质量对承担多种应用的网络计算环境是非常重要的,承担这个服务的计算机硬件必须有能力保障服务质 量。这个服务首先要有一定的容量,能响应单位时间内合理数量的服务器请求,同时这个服务对单个服务请求的响应时间要尽量快,还有这个服务要在要求的时间范 围内一直存在。

      如果一个WEB服务器只能在1分钟里处理1个主页请求,1个以外的其他请求必须排队等待,而这一个请求必须要3分钟才能处理完,同时这个WEB服务器在1 个小时以前可以访问到,但一个小时以后却连接不上了,这种WEB服务器在现在的Internet计算环境里是无法想象的。

      现在的WEB服务器必须能够同时处理上千个访问,同时每个访问的响应时间要短,而且这个WEB服务器不能停机,否则这个WEB服务器就会造成访问用户的流失。

  为达到上面的要求,作为服务器硬件必须具备如下的特点:性能,使服务器能够在单位时间内处理相当数量的服务器请求并保证每个服务的响应时间;可 靠性,使得服务器能够不停机;可扩展性,使服务器能够随着用户数量的增加不断提升性能。因此我们说不能把一台普通的PC作为服务器来使用,因为,PC远远 达不到上面的要求。这样我们在服务器的概念上又加上一点就是服务器必须具有承担服务并保障服务质量的能力。这也是区别低价服务器和PC的差异的主要方面。

      在信息系统中,服务器主要应用于数据库和Web服务,而PC主要应用于桌面计算和网络终端,设计根本出发点的差异决定了服务器应该具备比PC更可靠的持续 运行能力、更强大的存储能力和网络通信能力、更快捷的故障恢复功能和更广阔的扩展空间,同时,对数据相当敏感的应用还要求服务器提供数据备份功能。而PC 机在设计上则更加重视人机接口的易用性、图像和3D处理能力及其他多媒体性能。

图3.服务器系统架构图

7月13日

转载 什么是堆栈溢出

堆栈这个问题是这么引出的。

在农业信息监控那个项目中,采用了stc89c58rd+这个芯片,片外没有ram,当我定义了uchar xdata a[3000],程序不正常执行,后来修改了内存模式改为compact模式,可以了,在网上查了下,说是堆栈溢出的问题。为什么在large模式下会产生了堆栈溢出呢?

从物理上讲,堆栈是就是一段连续分配的内存空间。在一个程序中,会声明各种变量。静态全局变量是位于数据段并且在程序开始运行的时候被加载。而程序的动态的局部变量则分配在堆栈里面。

从操作上来讲,堆栈是一个先入后出的队列。他的生长方向与内存的生长方向正好相反。我们规定内存的生长方向为向上,则栈的生长方向为向下。压栈的操作push=ESP-4,出栈的操作是pop=ESP+4.换句话说,堆栈中老的值,其内存地址,反而比新的值要大。请牢牢记住这一点,因为这是堆栈溢出的基本理论依据。

在一次函数调用中,堆栈中将被依次压入:参数,返回地址,EBP。如果函数有局部变量,接下来,就在堆栈中开辟相应的空间以构造变量。函数执行结束,这些局部变量的内容将被丢失。但是不被清除。在函数返回的时候,弹出EBP,恢复堆栈到函数调用的地址,弹出返回地址到EIP以继续执行程序。

在C语言程序中,参数的压栈顺序是反向的。比如func(a,b,c)。在参数入栈的时候,是:先压c,再压b,最后压a.在取参数的时候,由于栈的先入后出,先取栈顶的a,再取b,最后取c。(PS:如果你看不懂上面这段概述,请你去看以看关于堆栈的书籍,一般的汇编语言书籍都会详细的讨论堆栈,必须弄懂它,你才能进行下面的学习)

好了,继续,让我们来看一看什么是堆栈溢出

运行时的堆栈分配

堆栈溢出就是不顾堆栈中分配的局部数据块大小,向该数据块写入了过多的数据,导致数据越界。结果覆盖了老的堆栈数据。

比如有下面一段程序:
程序一:
#include
int main ( )
{
char name[8];
printf("Please type your name: ");
gets(name);
printf("Hello, %s!", name);
return 0;
}

编译并且执行,我们输入ipxodi,就会输出Hello,ipxodi!。程序运行中,堆栈是怎么操作的呢?在main函数开始运行的时候,堆栈里面将被依次放入返回地址,EBP。我们用gcc -S 来获得汇编语言输出,可以看到main函数的开头部分对应如下语句:

pushl %ebp
movl %esp,%ebp
subl $8,%esp

首先他把EBP保存下来,,然后EBP等于现在的ESP,这样EBP就可以用来访问本函数的局部变量。之后ESP减8,就是堆栈向上增长8个字节,用来存放name[]数组。现在堆栈的布局如下:

内存底部     内存顶部
name    EBP   ret
<------ [ ]  [ ]  [ ]
^&name
堆栈顶部    堆栈底部

执行完gets(name)之后,堆栈如下:

内存底部    内存顶部
name    EBP   ret
<------ [ipxodi\\0 ] [ ]  [ ]
^&name
堆栈顶部     堆栈底部

最后,main返回,弹出ret里的地址,赋值给EIP,CPU继续执行EIP所指向的指令。

堆栈溢出

好,看起来一切顺利。我们再执行一次,输入ipxodiAAAAAAAAAAAAAAA,执行完
gets(name)
之后,堆栈如下:

内存底部     内存顶部
name    EBP ret
<------ [ipxodiAA] [AAAA]  [AAAA].......
^&name
堆栈顶部     堆栈底部

由于我们输入的name字符串太长,name数组容纳不下,只好向内存顶部继续写‘A’。由于堆栈的生长方向与内存的生长方向相反,这些‘A’覆盖了堆栈的老的元素。如图我们可以发现,EBP,ret都已经被‘A’覆盖了。在main返回的时候,就会把‘AAAA’的ASCII码:0x41414141作为返回地址,CPU会试图执行0x41414141处的指令,结果出现错误。这就是一次堆栈溢出。

在上面的例子中,这导致CPU去访问一个不存在的指令,结果出错。事实上,当堆栈溢出的时候,我们已经完全的控制了这个程序下一步的动作。如果我们用一个实际存在指令地址来覆盖这个返回地址,CPU就会转而执行我们的指令。

在UINX系统中,我们的指令可以执行一个shell,这个shell将获得和被我们堆栈溢出的程序相同的权限。如果这个程序是setuid的,那么我们就可以获得root shell。

7月11日

BSP 概念解析 (转载)

 

有的文章中把对各种处理器寄存器的操作和器件的驱动统称为bsp,所以很多提到与处理器有关。

 

 

 

下面是转载

 

Drew在这里按照自己的理解来解释一下BSP( Board Support Package),仅供参考:

  BSP是板级支持包,是介于主板硬件和操作系统之间的一层,应该说是属于操作系统的一部分,主要目的是为了支持操作系统,使之能够更好的运行于硬件主板。 BSP是相对于操作系统而言的,不同的操作系统对应于不同定义形式的BSP,例如VxWorks的BSP和Linux的BSP相对于某一CPU来说尽管实现的功能一样,可是写法和接口定义是完全不同的,所以写BSP一定要按照该系统BSP的定义形式来写(BSP的编程过程大多数是在某一个成型的BSP模板上进行修改)。这样才能与上层OS保持正确的接口,良好的支持上层OS。

例如:

VxWorks中的网卡驱动,首先在config.h中包含该网卡,然后将网卡含网卡的信息的参数放入数组 END_TBL_ENTRY endDevTbl [] 中,系统通过函数muxDevLoad( )调用这个数组来安装网卡驱动。

而在Linux中的网卡驱动,是在space.c中声明该网络设备,再把网卡驱动的一些函数加到dev结构中,由函数ether_setup()来完成网卡驱动的安装。

  纯粹的BSP所包含的内容一般说来是和系统有关的驱动和程序,如网络驱动和系统中网络协议有关,串口驱动和系统下载调试有关等等。离开这些驱动系统就不能正常工作。

  Tornado中BSP的编译和上层应用程序不同,用命令行或直接在Tornado环境下Build,在Tornado下不能跟踪调试。

  用户也可以添加自己的程序到BSP中,但严格来说不应该算BSP.一般来说这种做法不建议。因为一旦操作系统能良好运行于最终的主板硬件后,BSP也就固定了,不需要做任何改动。而用户自己在BSP中的程序还会不断的升级更新,这样势必对BSP有不好的影响,对系统造成影响,同时由于BSP调试编译环境较差,也不利于程序的编译调试。

 

上层程序

Tools - Applications

I/O System

VxWorks Libraries

TCP/IP


 

Wind Kernel

BSP

 


SCSI Controllerr

Serial Controller

Clock Timer

Ethernet Controller

.. ..

硬件

 

BSP在嵌入式系统和Windows系统中的不同


  其实运行与PC机上的windows或linux系统也是有BSP的。只是PC机均采用统一的X86体系架构,这样一定操作系统(windows, linux..)的BSP相对x86架构是单一确定的,不需要做任何修改就可以很容易支持OS在x86上正常运行,所以在PC机上谈论BSP这个概念也没什么意义了。

  而对嵌入式系统来说情况则完全不同,目前市场上多种结构的嵌入式CPU(RISC)并存(PPC,ARM,MIPS....),为了性能的需要,外围设备也会有不同的选择和定义。一个嵌入式操作系统针对不同的CPU,会有不同的BSP,即使同一种CPU,由于外设的一点差别(如外部扩展DRAM的大小,类型改变),BSP相应的部分也不一样。
  所以根据硬件设计编写和修改BSP,保证系统正常的运行是非常重要的。


BSP和PC机主板上的BIOS区别

 

  BSP和PC机主板上的BIOS区别很大,BIOS主要是负责在电脑开启时检测、初始化系统设备(设置栈指针,中断分配,内存初始化..)、装入操作系统并调度操作系统向硬件发出的指令,它的Firmware代码是在芯片生产过程中固化的,一般来说用户是无法修改。其实是为下载运行操作系统做准备,把操作系统由硬盘加载到内存,并传递一些硬件接口设置给系统。在OS正常运行后,BIOS的作用基本上也就完成了,这就是为什么更改BIOS一定要从新关机开机。

  PC机BIOS的作用更象嵌入式系统中的Bootloader(最底层的引导软件,初始化主板的基本设置,为接收外部程序做硬件上的准备)。与 Bootloader不同的是BIOS在装载OS系统的同时,还传递一些参数设置(中断端口定义,...),而Bootloader只是简单的装载系统。

  BSP是和操作系统绑在一起运行在主板上的,尽管BSP的开始部分和BIOS所做的工作类似,可是大部分和BIOS不同,作用也完全不同。此外BSP还包含和系统有关的基本驱动(串口,网口...),此外程序员还可以编程修改BSP,在BSP中任意添加一些和系统无关的驱动或程序,甚至可以把上层开发的统统放到BSP中。

  而BIOS程序是用户不能更改,编译编程的,只能对参数进行修改设置。更不会包含一些基本的硬件驱动。



BSP在嵌入式开发中的位置和作用

BSP开发处于整个嵌入式开发的前期,是后面系统上应用程序能够正常运行的保证。

大概步骤如下:

1.硬件主板研制,测试。

2.操作系统的选定,BSP编程。

3.上层应用程序的开发。

BSP部分在硬件和操作系统,上层应用程序之间。所以这就要求BSP程序员对硬件,软件和操作系统都要有一定的了解。这样才能做好BSP编程。

熟悉工具方面:电表,示波器,逻辑分析仪。硬件仿真器,仿真调试环境。

语言方面:汇编语言,C语言。

7月1日

DRAM的理解

 
内存RAM的理解
无论是SRAM还是DRAM都是一个矩阵式的存储结构,有行地址和列地址。
SRAM的存储容量小,采用的是触发器的结构,所以掉电不丢失,但价钱昂贵,行线和
列线在地址线上是分开的。如A0~Ai为行地址,Ai~Aj为列地址。这和容量小是有必然关系的。
DRAM容量大,为什么?采用的是mos管储能的方式,结构简单,所以可以做到大容量,
但是漏电现象是不可避免的,所以需要定时刷新控制电路辅助。
采用的仍然是行列地址共同作用的方式,但容量大了,地址线势必变大,所以在DRAM中
,行线列线是复用的,通过RAS和CAS两个管脚信号决定是行地址还是列地址,
WE用来决定是读操作还是写操作。为1时进行读操作,为0时进行写操作。
采用这种DRAM进行设计时,处理器内部一般具有相应的电路与之配套,否则使用起来是很困难的。
在arm9上一般都会用到,在arm9处理器上有相应的管脚与之相连,所以连线非常简单。
上面这篇文章以实例介绍了DRAM的电路设计方法。不错。
 
而这个地址中的文章详细的介绍了内存的读写过程,很不错,虽然没看太明白。

arm 2440 学习笔记

 
三星2440开发板核心板主要包括 :
一个2440芯片,一个12M晶振,一个32.768KHZ的晶振。
    12M的晶振用来给arm内部所需的各种电路提供时钟,倍频到几百兆的频率。
    两种方式为arm内部提供所需的时钟,一种是通过晶振,第二种是通过外部时钟        EXECLK,选用一种时另一种接高电平。
    OM[0,1]管脚复位时的高低电平决定了芯片的工作模式。
一个MIC5219,电源芯片提供了1.3v的电压。
两片HY57V561620 SDRAM,组成了64Mram。
一片nandflash K9F1208 ,64M。nandflash 均为串行flash。容量大。
 
以上这些就是核心板,3.3V电源是从主板引过来。
这个核心板子上要学习的就是ram和flash的引线。地址线,数据线的连接。
6月22日

项目经理(转)

1.政治素质。具有高度责任心和事业心,坚韧不拔,勇于进取的精神.

    2.能力素质.能力素质是项目经理整体素质体系中的核心素质。它表现为项目经理把知识和经验有机结合起来运用于项目管理的过程,对于现代项目经理来说,知识和经验固然十分重要,但是归根结底要落实在能力上。能力是直接影响和决定项目经理成败的关键,概括起来,包括五个方面:

    (1)决策能力。决策能力集中体现在项目经理的战略战术决策能力上。工程项目大都面临错综复杂、竞争激烈的外部环境,要使项目管理成功,经理人员应了解和研究环境,对与项目管理有关的技术、设备、材料等商情进行分析预测,制定出战略决策,并付诸实现。从决策程度来看,经理人员的决策能力可分解为如下三种:收集与筛选信息的能力、确定多种可行方案的能力、择优决策的能力。

    (2)组织能力。项目经理的组织能力是指设计组织结构,配备组织成员以及确定组织规范的能力。显然,拥有较高组织能力的经理人员能够运用组织理论原理,建立科学的、分工合理的、配套成龙的高效精干的组织机构,合理配备组织成员,确定一整套保证组织有效运转的规范。能够做到知人善用。

    项目经理的激励能力与经理人员对人的认识有关。现代人不单纯是“经济人”,而且是“社会人”,不仅有经济上的需求,而且有社会和心理上的要求。经理人员应更加注意运用各种社会和心理刺激手段,通过丰富工作内容、民主管理等措施来激励和调动员工的士气。

    3.知识素质。项目管理者的知识素质以及对项目管理活动的影响作用,构成项目领导人的专门能力有技术能力、商业能力、财务能力、管理能力、安全能力等。每一种能力都是以知识为基础的.因此.理想的项目经理应该有解决问题所必要的知识。根据理论探讨和项目经理实践经验的分析,项目经理应具备两大类知识,即基础知识与业务知识.

    (1)基础知识。基础知识包括社会科学和自然科学。在社会科学方面,应掌握经济学、管理学、心理学、法律和伦理学等方面的知识。在自然科学方而,应学好数学、物理学、化学和电子计算机使用等知识。

    (2)业务知识。项目经理应掌握投资学、投资项目管理学、技术经济学、企业领导学以及本行业的专业知识等。

    由此可知,项目经理应该是具有一定知识广度的“杂家”,他应在实践中不断深化和完善自己的知识结构.

    4.体格素质。身体健康,精力充沛.

    项目经理应具备的素质有六条:

    (1)具有本专业技术知识;

    (2)有工作干劲,主动承担责任;

    (3)具有成熟而客观的判断能力,成熟是指有经验,能够看出问题,客观是指他能看到最终目标,而不是只顾眼前;

    (4)具有管理能力;

    (5)诚实可靠与言行一致,答应的事就一定做到;

(6)机警、精力充沛,能够吃苦耐劳,随时都准备着管理可能发生的事情. 

项目监控(转载)

 1Critical Chain
    对于软件项目来说,关键是能否在规定的时间之内,预定的资金内,有质量的交付客户要求的产品。我们这里关注的是如何准时的完成项目,预算和质量都有其特定的系统去监控。能否按时完成项目就取决于我们的网络图中最长的那条chain,所以我们说一个项目网络图中最长的那条chain我们就称之为Critical Chain, 简称为cc。
    在一个项目的pert char未定之前,我们要做的就是反复分析最终得到cc,具体就是先找出最长的chain,然后分析每个task的duration是否都是不可再缩减的,若可以就进行优化,再看这条chain还是不是最长的chain,如果不是则找出新的最长的chain,依次类推,最终得到最优的网络图,得到cc。当然在项目的执行过程中,可能最初的cc慢慢的不再是最长的chain了,但是由于buffer机制管理的问题,cc一旦确立,在项目的执行过程将不再改变。有关buffer的问题在后面解释。
    cc确立后,就是整个项目的constraint,对于cc就要更多的关注与控制,也就一个项目的主要矛盾。非cc的task就是次要矛盾,但是不意味着就不重要,只是相对而言要更关注cc而已。 
2 Buffer
    人在做事情的时候,当需要预估这件事情完成所需的周期时,会有两种方式在脑中思考:50%confidence and 90%confidence, 50% confidence是指在最好的情况下,我尽最大的努力完成这个任务所需要的时间;90% confidence是指我有相当大的把握完成这个任务所需要的时间。出于人的惰性以及害怕一旦无法如期完成所带来的后果,大多数的人在预估完成任务所需要的时间的时候,倾向于使用90%confidence。而实际是90%confidence的时间偏长,往往造成项目周期的加长;50%confidence则由于过于不给自己留有余地,往往在意外情况发生的时候造成任务超时。所以我们引入buffer的概念来平衡,既有一定的把握完成,同时又避免50%所带来的高风险,又不像90%那样延长了工期。
    Buffer是指在某条链上所有的tasks最后加上一个task,给予一定的duration用于保护项目,避免突发事件造成的项目延期。例如一条链上有4个tasks,每个task 10days,则在最后一个task后再加上一个task,给上一定的时间,比如10days。如果有一个task在预计的10天内没有完成,而是用了12天,那么这个task就吃掉了2天的buffer,这时候buffer的 consumption就是2/10=20%. 在这里每个task的时间都是采用的50%confidence标准定的,而buffer就起到了降低了50%所带来的高风险。同时由于只有一个buffer,所以buffer是团队共享的buffer,这个时候个人消耗buffer就是消耗整个团队的buffer,即使PM不看着,team的其他成员也会注意的,而吃buffer的这个人所得到的压力就不只是来自PM了。:) 
3 Buffer management
    Buffer的另外一个重要的作用就是显示整个项目的状态。buffer如果没有被吃,那么整个项目的risk相对就低,如果buffer面临被吃完的局面,则说明buffer的保护作用已经慢慢消失,risk慢慢的在上涨。如果我们依照buffer consumption的比率设定一些值,如30%以下为绿色,30%~70%为黄色,70%~80%为红色。那么我们就可以依照这些颜色来简单的确定项目的状态,从而制定相应的对策。 
4 As late as possible
    大家有没有这种感觉,毕业前要交一个论文,你提前一个月写往往是在期限的前一天刚刚搞定;而如 late as possible
    大家有没有这种感觉,毕业前要交一个论文,你提前一个月写往往是在期限的前一天刚刚搞定;而如果你提前2周写,往往又是也很可能刚刚在期限的前一天搞定。这也是人的惰性的因素所致。所以有一种叫as late as possible的方法,不管这个项目什么时候开始,我们只是考虑在最好情况下,当所有的tasks的duration定下来了,buffer的大小定下来了,我们依据项目结束的日期从后往前推,从而得到项目开始的日期,如果这个日期晚于今天,那么可以考虑将resource放到别的项目中去。这种方法最早主要用于物流方面,因为仓库的占用是要花费相当的成本的,如果能很好的利用ALAP,则可以更有效率的利用仓库,降低成本。如今用于软件领域也可以使用。