2009-02-22

Windows Server 2008的注册表结构

Windows Server 2008的注册表结构:

  • HKEY_CLASSES_ROOT:用于管理文件系统,指定了Windows中某扩展名的应用程序的文件类型和打开这个文件要调用的程序。和HKEY_LOCAL_MACHINE\SOFTWARE\Classes是一样的,另外简称HKCR。详细文档:http://msdn.microsoft.com/en-us/library/ms724475(VS.85).aspx
  • HKEY_CURRENT_USER:包含系统当前用户的信息,在用户登录系统的时候从HKEY_USERS里把对应的项拷贝到HKEY_CURRENT_USER拷贝过来。
  • HKEY_LOCAL_MACHINE:管理当前系统的硬件配置,是对所有用户都有效的设置,简称HKLM
  • HKEY_USERS:管理系统的用户信息。在这个根键中保存了本地口令列表中的用户标识和密码列表,同时每个用户的预配置信息都被保存在这里。
  • HKEY_CURRENT_CONFIG:管理当前用户的系统配置。在这个根键中,保存着定义当前用户桌面配置的数据,改用户使用过的文档列表等等。

常用子键:

  • HKLM\SOFTWARE\Microsoft\Windows\currentVersion\Uninstall:程序的卸载信息
  • HKLM\SYSTEM\currentControlSet\Control\keyboard Layout:当前语言和输入法信息
  • HKLM\SYSTEM\CurrentControlSet\Services\Class:保存计算机设备类型目录,就是整台机器的硬件信息
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer:\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders:保存计算机中个人文件夹收藏夹的路径
  • HKLM\SOFTWART\Microsoft\Windows\CurrentVersion\Run:保存由控制面板设定的启动时运行程序的名称

注册表的键值格式为:键值名:数据类型:键值

  其中键值可以是:

  • 字符串值(S):一般表示文件的描述硬件标识什么的。
  • 二进制值(B):无长度限制。以HEX的形式显示
  • DWORD值(D):32位长的数值

REG文件格式:

很简单,你可以直接导出来学习。

Windows Registry Editor Version 5.00

[HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\Cache\Content]@=”tes“
"CachePrefix"="00000test"
"CacheLimit"=dword:0000c800"SavedLegacySettings"=hex:46,00,00,00,1f,00,00,00,09,00,00,00,00,00,00,00,00,\00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
  00,00,00,00,00,00,00,00,00,00,00,00,00,00
"testAddress"="C:\\regedit\\test.reg"
"testAddress"=-

使用REG文件可以操作主键和键值。

  • 添加主键直接在[]里面打出主键的路径即可比如[HKEY_USERS\.DEFAULT\Software\Microsoft\test]
  • 删除只需要在前面加个-即可,比如:[-HKEY_USERS\.DEFAULT\Software\Microsoft\test],注意删除的时候会把整个主键下所有东西都删掉。
  • 添加键值:添加字符串直接用双引号引起来,就像上面那个"CachePrefix"="00000test"一样,添加DWORD数据需要dwork:date,就像上面一样。如果添加二进制数据则是hex:date上面那个\是继续下一行的意思。要设置默认值的键值数据就需要用@符号。
  • 删除键值:只需要写”键值“=-即可,比如上面最后一句就是删除testAddress键



2009-02-21

[转]总结几条用Word排论文的技巧

  插公式时经常需要让公式居中对齐、行末的公式编号右对齐。只要设一个居中制表位和一个右对齐制表位,输入时按TAB即可。建议居中制表位位置用字符做单位,比如五号字体在缺省A4页面上是每行40字符,居中制表位就可以设在20字符处。
  我的公式编号用SEQ域输入,从“插入”菜单选“域”即可。这样做的好处是如果我有100个公式,在最开始插入一个新的,那么这100个公式的编号都要加1。
  如果手工修改会非常耗体,而Ctrl+A全部选定再F9更新域则十分快捷。
  参考文献用尾注,也在“插入”菜单里。缺省的是上标格式,按Ctrl+'+'可以改成正常格式。好处也是可以自动排号。
  图片说明用题注。一般排版要让题注宽度小于版心距,我用水平标尺上的悬挂缩进加右缩进实现。
  Word表格中可以进行简单的计算。比如我有一个表格,让第三列的值显示第二列比第一列多百分之几,用“表格”菜单的“公式”即可,不用Excel高射炮轰蚊子。
  对公式、尾注、图片、表格的引用一概用交叉引用,“插入”菜单下。好处是可以做成超级链接,而且公式编号改动的话对这个公式的引用会跟着改。
  所有的章节标题都用样式,并且用多级项目符号列表。好处是标题编号(第几章、第几节)可以自动生成,可以在文档结构图(“视图”菜单)中浏览,可以用垂直滚动条下方的定位按钮快速定位,还可以生成目录。我一般关闭“基于所用格式定义样式”这个自作聪明的功能,所有样式都自己选。
  我的图片和表格做成嵌入式的,这样不会乱跑。表格每个单元格水平垂直均居中对齐(Word 2000新增功能)。表格段落格式选“段中不分页”,这样不会出现表格拆到两页上的恶心局面。
我的正文缺省样式是首行缩进2字符。输公式的时候要另起一行,但是逻辑上它应该跟前面的文字算作一段(鼠标三击可以选定段),我用Shift+Enter 小回车搞定。每次要输入公式的时候,点到前一个包含公式的段,用格式刷复制即可。 先写这么多,以后有新的再补充,也欢迎大家补充。
  用Word编辑论文的几个建议 由于各方面的原因,大家主要还是用Microsoft Word (以下简称Word)编辑论文。Word在写科技论文方面虽然有一些先天不足,但却提供了非常强大的功能。如果不能充分利用这些功能,可能经常要为不断地调整格式而烦恼。我把自己以前使用Word的经验和教训总结一下,抛块砖。
  原则: 内容与表现分离 一篇论文应该包括两个层次的含义:内容与表现,前者是指文章作者用来表达自己思想的文字、图片、表格、公式及整个文章的章节段落结构等,而后者则是指论文页面大小、边距、各种字体、字号等。相同的内容可以有不同的表现,例如一篇文章在不同的出版社出版会有不同的表现;而不同的内容可以使用相同的表现,例如一个期刊上发表的所有文章的表现都是相同的。这两者的关系不言自明。在排版软件普及之前,作者只需关心文章的内容,文章表现则由出版社的排版工人完成,当然他们之间会有一定交互。Word 倡导一种所见即所得(WYSIWYG)的方式,将编辑和排版集成在一起,使得作者在处理内容的同时就可以设置并立即看到其表现。可惜的是很多作者滥用WYSIWYG,将内容与表现混杂在一起,花费了大量的时间在人工排版上,然而效率和效果都很差。 本文所强调的“内容与表现分离”的原则就是说文章作者只要关心文章的内容,所有与内容无关的排版工作都交给 Word 去完成,作者只需将自己的排版意图以适当的方式告诉 Word。因为Word不仅仅是一个编辑器,还是一个排版软件,不要只拿它当记事本或写字板用。主要建议如下。
  一定要使用样式,除了Word原先所提供的标题、正文等样式外,还可以自定义样式。如果你发现自己是用选中文字然后用格式栏来设定格式的,一定要注意,想想其他地方是否需要相同的格式,如果是的话,最好就定义一个样式。对于相同排版表现的内容一定要坚持使用统一的样式。这样做能大大减少工作量和出错机会,如果要对排版格式(文档表现)做调整,只需一次性修改相关样式即可。使用样式的另一个好处是可以由Word 自动生成各种目录和索引。

  1. 一定不要自己敲编号,一定要使用交叉引用。如果你发现自己打了编号,一定要小心,这极可能给你文章的修改带来无穷的后患。标题的编号可以通过设置标题样式来实现,表格和图形的编号通过设置题注的编号来完成。在写“参见第x章、如图x所示”等字样时,不要自己敲编号,应使用交叉引用。这样做以后,当插入或删除新的内容时,所有的编号和引用都将自动更新,无需人力维护。并且可以自动生成图、表目录。
  2. 一定不要自己敲空格来达到对齐的目的。只有英文单词间才会有空格,中文文档没有空格。所有的对齐都应该利用标尺、制表位、对齐方式和段落的缩进等来进行。如果发现自己打了空格,一定要谨慎,想想是否可以通过其他方法来避免。同理,一定不要敲回车来调整段落的间距。
  3. 绘图。统计图建议使用Execel生成,框图和流程图建议使用Visio画。如果不能忍受Visio对象复制到Word的速度,还可以试试 SmardDraw,功能不比Visio弱,使用不比Visio难,速度却快多了。如果使用Word的绘图工具绘图,最好以插入Word图片的方式,并适当使用组合。
  4. 编辑数学公式建议使用 MathType5.0,其实Word集成的公式编辑器是它的3.0版。安装MathType后,Word会增加一个菜单项,其功能一目了然。一定要使用 MathType 的自动编号和引用功能。这样首先可以有一个良好的对齐,还可以自动更新编号。Word 正文中插入公式的一个常见问题是把上下行距都撑大了,很不美观,这部分可以通过固定行距来修正。
  5. 参考文献的编辑和管理。如果你在写论文时才想到要整理参考文献,已经太迟了,但总比论文写到参考文献那一页时才去整理要好。应该养成看文章的同时就整理参考文献的习惯。手工整理参考文献是很痛苦的,而且很容易出错。Word没有提供管理参考文献的功能,用插入尾注的方法也很不地道。我建议使用 Reference Manager,它与Word集成得非常好,提供即写即引用(Cite while you write,简称Cwyw)的功能。你所做的只是像填表格一样地输入相关信息,如篇名、作者、年份等在文章中需要引用文献的的方插入标记,它会为你生成非常美观和专业的参考文献列表,并且对参考文献的引用编号也是自动生成和更新的。这除了可以保持格式上的一致、规范,减少出错机会外,更可以避免正文中对参考文献的引用和参考文献列表之间的不匹配。并且从长远来说,本次输入的参考文献信息可以在今后重复利用,从而一劳永逸。类似软件还有Endnote和Biblioscape。 Endnote优点在于可以将文献列表导出到BibTeX格式,但功能没有Reference Manager强大。可惜这两个软件都不支持中文,据说 Biblioscape对中文支持的很好,我没有用过,就不加评论了。
  6. 使用节。如果希望在一片文档里得到不同的页眉、页脚、页码格式,可以插入分节符,并设置当前节的格式与上一节不同。
  7. 上述7点都是关于排版的建议,还是要强调一遍,作者关心的重点是文章的内容,文章的表现就交给Word去处理。如果你发现自己正在做与文章内容无关的繁琐的排版工作,一定要停下来学一下Word的帮助,因为Word 早已提供了足够强大的功能。
  8. 我不怀疑Word的功能,但不相信其可靠性和稳定性,经常遇到“所想非所见”、“所见非所得”的情况让人非常郁闷。如果养成良好的习惯,这些情况也可以尽量避免,即使遇上,也可以将损失降低到最低限度。建议如下:
  9. 使用子文档。学位论文至少要几十页,且包括大量的图片、公式、表格,比较庞大。如果所有的内容都保存在一个文件里,打开、保存、关闭都需要很长的时间,且不保险。建议论文的每一章保存到一个子文档,而在主控文档中设置样式。这样每个文件小了,编辑速度快,而且就算文档损坏,也只有一章的损失,不至于全军覆灭。建议先建主控文档,从主控文档中创建子文档,个人感觉比先写子文档再插入到主控文档要好。
  10. 及时保存,设置自动保存,还有一有空就ctrl+s。
  11. 多做备份,不但Word不可靠,windows也不可靠,每天的工作都要有备份才好。注意分清版本,不要搞混了。Word提供了版本管理的功能,将一个文档的各个版本保存到一个文件里,并提供比较合并等功能。不过保存几个版本后文件就大得不得了,而且一个文件损坏后所有的版本都没了,个人感觉不实用。还是多处备份吧
  12. 插入的图片、和公式最好单独保存到文件里另做备份。否则,哪天打文档时发现自己辛辛苦苦的编辑的图片和公式都变成了大红叉,哭都来不及了。

    其他建议:
  13. 使用大纲视图写文章的提纲,调整章节顺序比较方便
  14. 使用文档结构图让你方便的定位章节
  15. 使用文档保护,方便文章的审阅和修改
上面的建议并不全面,但相信比较管用。如果还有疑问,自己花些时间研究一下Word的帮助,相信会有事半功倍的效果

2009-02-19

Linux下转换视频文件Mencoder篇。续

  之前那篇已经太长了,再修改数据丢失的风险太大,所以就新开了一帖。如果有需要可以先看下旧的那篇

关于h.264编码
  去年底我曾经详细的通过实际压缩出来的结果对比研究和几个星期的x264编码的效果。但是可惜的是当时忙于项目,没有记录,现在要用时发现信息已经丢掉甚多,实为可惜。所以先整理一小部分还找的到的资料。
  h.264编码几乎是现在的一种国际标准了,连那个啥dobe的flash 都能够直接解码了,就这一点就比Silverlight强了很多。
  首先看一下编码参数:
mencoder test.avi -o /dev/null -oac copy -ovc x264 -x264encopts pass=1:turbo:me_range=16:qp_max=51:brdo:ratetol=1.0:bitrate=1000:me=umh:partitions=p8x8,b8x8,i8x8,i4x4:qp_min=10:bframes=1:qp_step=4:direct_pred=auto && mencoder test.avi -o testssdfsd.avi -oac lavc -lavcopts acodec=ac3:abitrate=96 -ovc deadzone_inter=21:pass=2:me_range=16:qcomp=0.6:qp_max=51:brdo:chroma_me:vbv_init=0.9:ratetol=1.0:bitrate=1000:me=umh:partitions=p8x8,b8x8,i8x8,i4x4:chroma_qp_offset=0:subq=5:pb_factor=1.3:deblock=0,0:qp_min=10:ip_factor=1.4:cabac:bframes=1:frameref=5:qp_step=4:b_adapt:b_bias=0:trellis=1:direct_pred=auto:nr=0:deadzone_intra=11:keyint_min=25:keyint=250

  这个是我研究出来看起来效果相对不错的编码参数,但是未必是最好的。码率的指定我没有研究,这里指定1000是为了做基准对比。
注:以上编码参数有漏掉,待我找到原来的再补上,你可以先在ovc后面加 x264enc -x264encopts
  首先可以确定的一点是2 pass的编码效果肯定比1 pass能强上一点,主要原因是2 pass在第一轮的对视频文件的测试中能够使第二轮真正编码的时候更加充分的利用码率,就是把码率用在刀刃上。
  参数解释:第一阶段的编码,文档的解释是收集视频上的统计信息,并将这些信息写入一个文件中。 除了那些默认为打开的选项,你可能想关闭一些消耗CPU的选项。这里我使用turbo能够加快速度,本来turbo有两个值可以选的turbo=1或turbo=2,1对最终编码质量没有影响,二有一点小影响,1最大能把速度加快到2倍,2就能4倍了,由于turbo选项会减小subq、frameref的值,所以我们就没必要在第一阶段设置这两个值了。
  第二阶段的编码就可以把要的全开开了。这里不重复说明了,以前的帖子里有解释,看这个

  最后,补充一下关于需要使用flash播放264编码的相关知识,首先,官方推荐方案是h.264+aac,封装可以使用flv或mp4,但是如果你在写flex的时候两种格式似乎在加载代码上有不同,可以参考这个帖子,flv的格式标准可以从这里下载。未免那个连接挂了,这里引用一句里面最精华的内容:

在FLEX中一般都用videoDisPlayer这个控件播放视频文件,通过使用source属性设置进行播放flv文件,如:rtmp://123.32.4.22:1935/fms/aa.flv.
但如果播放MP4格式文件如是aa.mp4,还可以使用videoDisPlayer,但不同的地方在source赋值,应该这么写:rtmp://123.32.4.22:1935/fms/MP4:aa
-----------------------------------------
关于封装:
  mencoder本生支持的封装格式有限,不过通过使用libavformat获得了很多封装格式的支持。
你可以使用
mencoder -of help
这个命令获得你的mencoder支持的封装格式。显然,这里相当少:
Available output formats:
avi - Microsoft Audio/Video Interleaved
mpeg - MPEG-1/2 system stream format
lavf - FFmpeg libavformat muxers
rawvideo - (video only, one stream only) raw stream, no muxing
rawaudio - (audio only, one stream only) raw stream, no muxing

但是,命运是能够改变的。当你使用lavf的时候,程序会根据你的扩展名自动判别封装格式,最新的官方文档有详细的说明:
libavformat container nameDescription
mpgMPEG-1 and MPEG-2 PS
asfAdvanced Streaming Format
aviAudio-Video Interleaved
wavWaveform Audio
swfMacromedia Flash
flvMacromedia Flash video
rmRealMedia
auSUN AU
nutNUT open container (experimental and not yet spec-compliant)
movQuickTime
mp4MPEG-4 format
dvSony Digital Video container
mkvMatroska open audio/video container

  所以呢,结果就是,你可以任意使用这些封装格式,只需要-of lavf即可。
/*-----------------------------------------------------*/
*原创文章,转载请保留指向本文的连接
/*-----------------------------------------------------*/

2009-02-15

Mencoder转换RMVB、wmv等视频为FLV的注意事项

经过多日的编码参数测试,最终找到了比较不错的解决方案,趁着这次重写代码的机会,把编码参数也调整下。
原来使用的flv编码参数是这样的:
mencoder -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -oac mp3lame -lameopts abr:br=56 -ovc lavc -lavcopts vcodec=flv:mbd=2:mv0:trell:v4mv:cbp:last_pred=3:dia=4:cmp=6:vb_strategy=1:vbitrate=500 -vf scale=320:240 -ofps 12 -srate 22050 /tempvideo/813f77fa8bbd055850d1b84d0e95f7e2.wmv,19:-o /raid/data_post/flvtemp/813f77fa8bbd055850d1b84d0e95f7e2.flv


  如果你阅读过mencoder的手册的话你就会发现这里有些不合理的参数,比如oac指定了mp3lame却有调用的是lameopts。经过稍微的修改之后,我采用的编码参数是这样的:

mencoder -ovc lavc -lavcopts vcodec=flv:vbitrate=500:mbd=2:last_pred=3:cmp=3:trell:v4mv:cbp:qprd:mv0 -oac mp3lame -lameopts aq=3:preset=64 -vf expand=352::::::,scale=352:-3 -lavdopts er=2 -pp 6 -of lavf -srate 44100 -ofps 12 -mc 0 upload_save_sends/0becb057bd6a1d7f0b72feea8a032c42.avi -o /flvtemp/0becb057bd6a1d7f0b72feea8a032c42.flv


  这样稍微提高了一些视频的品质,但是用的是更多的编码时间来交换的,然而,之前在做桑梓电影的自动转换程序的时候,经过研究,发现,即使是不到1M的码率,使用h.264编码的视频能够达到非常高的清晰度,所以,最佳的解决方案还是尽快利用flash10支持h.264播放的特性更换旧的flv。

在调试参数的过程中。用于在线视频网站的flv有如下两个问题:

  1. rmvb、wmv等视频转换时会有很多的duplicated frame,这种视频经常会造成声音画面不同步,解决方法有两个。一是,保证-ofps 是12,这样一般就能同步,如果还不行使用解决方法二:使用mencoder转换成avi容器的其他编码,再用ffmpeg转换成flv。另外,在2008年12月之后ffmpeg也加入了real video的解码支持,但是暂时还是有一点bug,所以我们等其稳定了之后就可以直接用ffmpeg编码了。
  2. flv视频在播放器上不能拖动,这是由于没有元数据的原因,使用flvtool2或者fixmdi修复一下即可。

最近实际项目过程中的一些经验

  连续做了两个小型项目,累计了4000多行的java代码,自然也从中获得了一些实践经验。

  1. 关于java.lang.process:
    用这个类来产生子进程是不错,不过我发现只要我不获取子进程的输出流(getInputStream),我调用的mencoder就会挂死在那里,查了一下文档:创建的子进程没有自己的终端或控制台。它的所有标准 io(即 stdin,stdout,stderr)操作都将通过三个流 (getOutputStream(),getInputStream(),getErrorStream()) 重定向到父进程。因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁。所以,只需要接受输出流并不处理就好了,注意stdout对应的是getInputStream
  2. 远程方法调用(RMI)获得了一个服务器上的对象但是如果这个对象包含了所谓的static field 静态字段的话,客户端上这个静态类字段是空的,如果一定要用到它的话,在客户端实例化一次这个类就好。
  3. rmi获得的对象如果是null的话,会被认为是异常
  4. 扫描文件获得参数需要比较繁琐的字符串操作,应该找到一种更加简单的方法。
  5. process.waitfor()方法应该放在输入输出和错误流的后面,否则程序会一直阻塞到执行结束,而且还可能产生缓冲区满了导致调用的外部进程挂起.

2009-02-10

Solaris 10的信号列表和基本常识

以下就是一张比较完整的Solaris的信号列表:


信号名称 编号 默认处理 描述
SIGHUP 1 Exit 挂起(参加termio(7))
SIGINT 2 Exit 中断(参加termio(7))
SIGQUIT 3 Core 退出(参加termio(7))
SIGILL 4 Core 非法指令
SIGTRAP 5 Core 跟踪或断点异常
SIGABRT 6 Core 异常终止
SIGEMT 7 Core 模拟异常
SIGFPE 8 Core 浮点算数运算异常
SIGKILL 9 Exit 杀掉进程,不能被捕获或忽略
SIGBUS 10 Core 总线错误,不对界地址错误
SIGSEGV 11 Core 段错误——通常是访问非法地址空间
SIGSYS 12 Core 错误的系统调用
SIGPIPE 13 Exit 错误管道
SIGALRM 14 Exit 报警时钟
SIGTERM 15 Exit 终止
SIGUSR1 16 Exit 用户定义的信号1
SIGUSR2 17 Exit 用户定义的信号2
SIGHLD 18 Ignore 子进程状态改变
SIGPWR 19 Ignore 电源失效或重新启动
SIGWINCH 20 Ignore 窗口大小改变
SIGURG 21 Ignore 紧急socket情况
SIGPOLL 22 Exit 可以查询的事件(streamio(7))
SIGIO 22 Exit aioread/aiowrite完成
SIGSTOP 23 Stop 停止(不能被捕获或忽略)
SIGTSTP 24 Stop 停止(作业控制)
SIGCONT 25 Ignore 继续
SIGTTIN 26 Stop 停止——tty输入
SIGTTOU 27 Stop 停止——tty输出
SIGVTALRM 28 Exit 时钟报警——setitimer(2)ITIMER_VIRTUAL报警
SIGPROF 29 Exit Profiling报警——setitimer(2)ITIMER_PROF、ITIME_REPROF
SIGXCPU 30 Core 超出了CPU时间限制
SIGXFSZ 31 Core 超出了文件大小限制
SIGWAITING 32 Ignore 并发信号,Solaris10之前的线程库使用
SIGLWP 33 Ignore 内部LWP信号,Solaris10之前的线程库使用
SIGFREEZE 34 Ignore 检查点挂起
SIGTHAW 35 Ignore 检查点继续
SIGLCANCEL 36 Ignore 撤销
SIGLOST 37 Ignore 资源丢失
SIGRTMIN 38 Exit 优先级最低的实时信号
SIGRTMAX 45 Exit 优先级最高的实时信号

  对于信号,Solaris定义了4种默认的处理例程:
  • Exit:终止进程
  • Core:创建进程的内核映像文件并终止进程
  • Stop:挂起进程的执行(通常用于作业控制或调试)
  • Ignore:丢弃信号,不采取任何操作,即使信号被阻塞

实际上,除了SIGKILL和SIGSTOP这两个信号外,程序是可以改变其他信号的处理例程的。这就具体要看程序作者是如何处理的了。

  虽然信号有这么多,但是实际上信号还分做同步信号和异步信号:

  • 同步信号也叫异常信号来自于内核的异常处理例程,担任就是程序内部有问题或者它使用的硬件有问题产生的(这里有问题不是坏掉,比如等待也可是一种)。
  • 异步信号一般来自于用户命令,程序和内核的其他地方,比如我们用kill命令发送信号给进程,或者使用快捷键Control+Z来作业控制等等

2009-02-08

Subversion的超快速入门

  前几天成功的在Sourceforge.net上面注册了一个项目,考虑到版本控制系统的诞生年代,我决定使用subversion。这个版本控制系统来管理源代码仓库(Repository),所以,稍微迅速的瞄了一眼svn的资料和使用方法,为了以后方便在这篇文章里稍微记下。如果你希望详细了解svn的话,请放轻松到这里去看整本书:http://www.subversion.org.cn/svnbook/

使用SVN的必备基本概念:
  Subversion是一个“集中式”的信息共享系统。版本库是Subversion的核心部分,是数据的中央仓库(Repository)。svn把你的源代码或者任何文档集中存储在一个仓库中,以树型目录的形式维护,可以有多个用户进入这个仓库来处理源代码。这个特性使得svn看起来就像一个文件服务器一样,那它和网络硬盘有什么不一样呢?关键之处在于svn不仅能够存储你的文件,还能够按照你更新、创建文件的时间等信息来保存你的每个修订版本。你可以在有任意需求的时候倒回到任意一个修订版本,怎么样?是不是和Google Docs的功能很像?这就是它的强悍之处。当然,据说还有很多牛逼烘烘的功能 。。不过我们初学者知道这些就够了。。这个就是版本控制。
  svn使用的版本模型:
  如果你学习过基本的编程或者操作系统的进程管理的知识你就不难理解:因为有很多人可能同时在修订某个文件的自己的版本,这个过程中,就可能产生同步化的问题,某A编辑了源码保存到仓库之后某B也编辑了源码保存到仓库,这个时候某B编辑的版本就把某A编辑的版本完全覆盖了,也就是某A这位仁兄修改了半天的结果完全作废了。
  为了解决这个问题,svn使用的模型是copy-modify-merge model也就是拷贝-修改-合并模型,这个模型使得每个用户从版本库里获得一份自己的本地项目拷贝(也就是下载一份到本地)然后修改本地项目拷贝,改完以后再向仓库申请合并修改,如果在这两个修订版之间有多个用户修改这个项目,那么svn会要求用户进行检查,最终合并到新的修订版本。

SVN的基本用法:
  好,了解了基本概念之后就可以很容易的使用svn了。一个典型的日常svn工作流程如下:

  • 更新你的工作拷贝

    • svn update :把你的工作拷贝与最新的版本同步(应该不是全部下载,而是把有被其他人更新的文件下载)

  • 做出修改(注意,这一阶段的命令都是对你本地项目拷贝的内容进行的,要更新到版本库需要你进行提交svn commit)

    • svn add :添加文件或目录或符号链接,如果你指定了一个目录,那么这个目录下的文件都会被添加,如果只想添加目录需要使用-non-recursiv参数

    • svn delete :删除文件或目录或符号链接,如果是文件夹的话,在你的本地项目拷贝里面不会立刻被删除,而是要等到你下一次提交的时候)

    • svn copy :顾名思义,拷贝东西svn copy source dest

    • svn move :顾名思义,移动东西,这里等同于拷贝后再删除

  • 检验修改(在提交之前检查一下你做过哪些修改,这些命令也对你本地工作目录进行)

    • svn status :查看修改

    • svn diff :查看修改的详细信息

使用svn status能看到一些信息,比如:

A stuff/loot/bloo.h # file is scheduled for addition
C stuff/loot/lump.c # file has textual conflicts from an update
D stuff/fish.c # file is scheduled for deletion
M bar.c # the content in bar.c has local modifications

ACDM分别代表addition conflict deletion modifications

  • 可能会取消一些修改

    • svn revert :取消修改,这个命令会把文件还原到上一次同步后的状态,当然也可以回复被你删掉的文件。

  • 解决冲突(合并别人的修改)

    • svn update :返回的结果前面的符号,U代表未改动,G代表已改动但没有重叠的地方,可以直接合并,C代表有冲突

    • svn resolved :你解决了冲突之后,使用这个命令通知服务器冲突已经解决。

  • 提交你的修改

    • svn commit

2009-02-07

CPU的进程管理

  作为基础知识,最近几天会稍微看看操作系统原理,所以会记录一些关于操作系统的东西。虽然我手头的这一本是Solaris原理,但是,之后回学校还有一本很厚的Windows原理。。。


  这里把CPU成为处理机,进程是处理机的基本概念,进程就是一个程序在一个数据集合上的一次动态执行的过程,所以,所谓进程,立竿见影的说法就是进程是程序的执行,是一种状态变化的过程。

  操作系统用来记录进程相关信息的一个数据接口就是进程控制块(process control block, PCB)这个东西包括进程描述信息、进程控制信息、资源占用信息和处理机现场保护结构:

  • 进程描述信息包括:进程标识符(process ID)、进程名、用户标识符(user ID)和进程组关系(process group)
  • 进程控制信息包括:当前状态、优先级、代码执行入口地址、运行统计信息(执行时间和页面调度)、进程阻塞原因等

  • 资源占用信息就是进程占用的系统资源列表

  • 处理机现场保护结构保存寄存器值(通用寄存器、程序计数器(PC)、状态字(PSW)、栈指针等)


进程的状态转换


  进程从创建到终止的过程是不断变化的,一般操作系统会把进程分成若干种状态,定义各种状态间转换的条件。我们先看一个单挂起进程模型:


  • New即进程创建
  • Admit即提交:进程创建后被提交,新的进程就进入了Ready的状态
  • Dispathc即调度运行:系统从就绪进程表中选择一个进程,进入运行状态
  • Release:进程执行完成或异常中断就会被release就进入Exit状态,异常中断被release时是Abort


  • Timeout:当本进程的时间片用完了或者这个进程被高优先级的进程打断了,就Timeout,进入Ready状态


  • Event Wait:进程要求的事件还没有出现,这个时候进程就被Blocked(阻塞)了,因而暂停运行了
  • Event Occur:进程等待的事件发生了,这个时候阻塞的进程就进入就绪队列
  • Suspend即挂起:从内存转到外存,在单挂起进程模型里,进程从阻塞到阻塞挂起,是由于没有进程处于就绪状态或者有就绪的进程要求更多的内存资源的时候,就会进行这种转换,以求能够提交新进程或运行就绪进程
  • Activate即激活:把一个进程从外存转到内存,在单挂起进程模型里,进程从阻塞挂起到就绪是由于被阻塞挂起的进程是目前优先级最高的进程。所以被系统开始执行。

  单挂起进程模型基本就是如此,而在双挂起进程模型中,情况复杂的多,但是原理也是一样,区别就是所有挂起的进程都必须要从就绪挂起的状态恢复,而进程初始化后也会检查是否有比自己优先级更高的进程在执行,有的话就先把自己就绪挂起了。只看图,不需多说明:




进程控制:

  操作系统对进程的控制是依据用户命令和系统状态来决定的,进程的控制就是进程状态的转换。

  操作系统完成初始化后系统就可以创建进程,在进程创建过程中,操作系统进行PCB的维护,每一个进程都可以利用系统调用功能来创建新的进程,创建者就是父进程,被创建的就是子进程,按照子进程是否覆盖父进程和是否加载新程序,子进程被分为三类:

  • fork:复制现有进程的上下文(之后会不同),产生新的进程

  • spawn:产生新进程,加载新程序

  • exec:加载新程序,覆盖自身,不产生新进程

  进程退出时,操作系统要负责删除系统维护的相关数据结构,并且回收资源。Solaris支持fork和exec这两类进程创建的系统调用,同时使用vfork来改善创建并加载新程序的性能。

  除了创建和推出,进程还有阻塞和唤醒的控制。当出现等待io或其他事件时进程会被阻塞。

  在Unix中,与进入阻塞的相关系统调用有:

  • sleep:暂停一段时间,在指定的时间内,本进程将被阻塞,程序上的返回值是实际的阻塞时间
  • pause:暂停并等待信号,本进程将等待信号,若收到信后后就恢复执行或终止进程(收到终止信号),程序上不返回

  • wait:等待子线程暂停或终止,本进程将被阻塞,等待子进程结束,当福进程创建多个子进程,并且有子进程退出了,父进程的wait函数将在第一个子进程结束的时候返回子进程的ID

  • kill:发送信号到某个进程或一组进程,Solaris中信号的定义在“/usr/src/bin/include/sys/signal.h"这个信号和kill命令发给进程的信号是一样的。


在操作系统中,进程的引入提高了系统资源的利用率,但是要进一步提高进程的并发性时,切换开销过大,使得进程间通信的效率收到很大限制,因此,就引入了线程,来简化进程间通信,提高进程内的并发程度。


  在引入线程的操作系统中,进程被作为资源分配的的那位,而线程才是处理机调度的对象。一个进程内部允许有多个并发执行的线程。一个线程是进程中的一个控制点,同一个进程内的各个线程可以访问这个进程的所有资源,且这些线程的上下文空间很多地方相同,所以能够大幅度简化内部通信。


  同进程相比,线程的优点在于,创建和终止快速,同进程内线程切换比进程切换快速,可以不通过内核进行通信。为了区分清楚线程和进程,我们必须注意他们的不同之处:


  • 地址空间资源方面:进程的地址空间是相互独立的,而同一进程内的各线程共享这个进程的地址空间

  • 通信关系方面:进程间通信需要使用操作系统提供的进程间通信机制,而同一进程内的各线程可以直接读写进程数据段来通信。

  • 调度切换:统一进程中的线程上下文切换比进程快得多

在操作系统中,对线程的支持也有不同的方式,其中一种是在操作系统的内核和用户程序两个层次提供线程的控制机制:


  • 内核线程(kernel-level thread):由内核创建和销毁,内核维护进程和线程的上下文信息,线程的切换有内核完成,如果一个内核线程由于io被阻塞,不会影响其他线程。此时处理机的时间片分配对象也是线程,多线程的进程能够获得更多的CPU时间。内核线程需要操作系统支持。

  • 用户线程(user-level thread):由应用进程利用线程库提供的函数来控制的线程。操作系统不必知道用户线程的存在。用户线程的切换不需要内核特权,线程调度算法可以为应用特别优化。但是由于系统不知道用户线程的存在,如果一个线程在进入系统调用后阻塞了,整个进程都必须等待。此外,处理机分配给进程的时间片是一定的情况下,线程多了,每个线程的CPU时间就少了。用户线程是不需要操作系统提供支持的,因此可以在不支持内核线程的系统中使用。

  • 轻量级进程(Light Weight Process):由内核支持的用户线程,一个进程可以有多个轻量级进程,每个轻量级进程由一个单独的内核线程来支持。由于同时提供内核线程控制和用户线程库,这种实现有着两者的有点。

  Solaris10是一个多线程系统,操作系统的任务以内核线程的形式执行。多线程进程中,用户线程和LWP一起创建,LWP是内核对象,他使用户线程能够独立于统一进程中的其他线程执行,并且能够进入内核,在Solaris中,内核线程是调度和执行的单位,因此进程中的用户线程必须链接到内核线程才能执行。在Solaris10中,线程模型使用的是1:1的模型,所有的线程都是LWP


  由于Solaris的这种机制,所以同上面介绍的一样,在Solaris中,进程被定义为线程的状态容器,因此,系统是按照进程来分配资源的,所以也就有了能够控制进程可使用资源的方法。在Solaris中,进程对象的名字是proc_t,用户可以使用进程文件系统的proc的命令获得进程的信息和控制进程。常用的系统命令 ps、prstat和proc都是在为文件系统/proc之上构建的。


进程的终止:

  1. 程序调用了exit函数,这个时候整个进程的所有线程都会被终止。线程调用了thr_exit,这个时候只有线程终止。

  2. 进程执行完毕

  3. 收到信号,被终止。

  当进程终止的时候,会执行内核退出函数,释放分配给进程的所有资源,进程进入SZOME(zombie)状态,等待父进程执行wait系统调用来收集退出状态,当wait执行完后,这个进程彻底消失。这个也是init进程继承sched进程的目的。