﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-快乐的天空-随笔分类-学习笔记</title><link>http://www.cppblog.com/HappySky2046/category/19399.html</link><description>时间来得快，去得也快</description><language>zh-cn</language><lastBuildDate>Wed, 10 May 2017 11:52:45 GMT</lastBuildDate><pubDate>Wed, 10 May 2017 11:52:45 GMT</pubDate><ttl>60</ttl><item><title>境界的提升</title><link>http://www.cppblog.com/HappySky2046/archive/2017/05/10/214925.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Wed, 10 May 2017 10:15:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2017/05/10/214925.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/214925.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2017/05/10/214925.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/214925.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/214925.html</trackback:ping><description><![CDATA[<div>工程师：<br />不断地思考与锤炼自身对最佳实践方式的理解感悟<br />设计过的系统架构图、功能结构图、数据库模型，并能基于系统实际使用情况进行基于架构的系统结构优化、性能优化等。<br /><br />苦行僧:</div><div>&nbsp;追求于设计之道与艺术之道的<br /><br />布道师:</div><div>有着广阔的见识与丰富的实战经验, 经过短暂的观察即可指出对于当前架构的优化意见，可以用最简单的办法解决技术上的难题，可以通过跨领域知识启迪你解决问题.<br /></div><div>科学家与哲学家<br />&nbsp;paper &amp; spirit</div><img src ="http://www.cppblog.com/HappySky2046/aggbug/214925.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2017-05-10 18:15 <a href="http://www.cppblog.com/HappySky2046/archive/2017/05/10/214925.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>shell 脚本</title><link>http://www.cppblog.com/HappySky2046/archive/2017/03/23/214774.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Thu, 23 Mar 2017 09:15:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2017/03/23/214774.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/214774.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2017/03/23/214774.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/214774.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/214774.html</trackback:ping><description><![CDATA[<span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">#数字段形式</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">for i in {1..100}</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">do</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">&nbsp;&nbsp; echo $i</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">done<br /><br /></span><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">#详细列出（字符且项数不多）</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">for File in 1 2 3 4 5&nbsp;</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">do&nbsp;</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">&nbsp;&nbsp;&nbsp; echo $File&nbsp;</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">done<br /></span><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;"><br />#对存在的文件进行循环</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">for name in 'ls *.log'</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">do&nbsp;</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name=`echo "$</span><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">name</span><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">" | awk -F. '{print $1}'`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo $name</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">done<br /><br /></span><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">#查找循环（ls数据量太大的时候也可以用这种方法）</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">for shname in `find . -type f -name "*.sh"`</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">do&nbsp;</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name=`echo "$shname" | awk -F/ '{print $2}'`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo $name</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">done</span><br /><br /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">#((语法循环--有点像C语法，但记得双括号</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">for((i=1;i&lt;100;i++))</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">do</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">&nbsp;&nbsp;&nbsp; if((i%3==0))</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">&nbsp;&nbsp;&nbsp; then</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo $i</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">&nbsp;&nbsp;&nbsp; fi</span><br style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;" /><span style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">done<br /><br /></span><p style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">#seq形式 起始从1开始<br />for i in `seq 100`<br />do<br />&nbsp;&nbsp;&nbsp; if((i%3==0))<br />&nbsp;&nbsp;&nbsp; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo $i<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue<br />&nbsp;&nbsp;&nbsp; fi<br />done</p><p style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">#while循环注意为方括号[],且注意空格<br />min=1<br />max=100<br />while [ $min -le $max ]<br />do<br />&nbsp;&nbsp;&nbsp; echo $min<br />&nbsp;&nbsp;&nbsp; min=`expr $min + 1`<br />done&nbsp;&nbsp;</p><p style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">#双括号形式，内部结构有点像C的语法，注意赋值：i=$(($i+1))<br />i=1<br />while(($i&lt;100))<br />do<br />&nbsp;&nbsp;&nbsp; if(($i%4==0))<br />&nbsp;&nbsp;&nbsp; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo $i<br />&nbsp;&nbsp;&nbsp; fi<br />&nbsp;&nbsp;&nbsp; i=$(($i+1))<br />done<br /><br /></p><p style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;">#从配置文件读取，并可以控制进程数量<br />MAX_RUN_NUM=8<br />cat cfg/res_card_partition.cfg |grep -v '^$'|grep -v "#" | grep -v grep |while read partition&nbsp;<br />do&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nohup sh inv_res_card_process.sh $partition &gt;log/resCard$partition.log 2&gt;&amp;1 &amp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while [ 1 -eq 1 ]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; psNum=`ps -ef | grep "inv_res_card_process" | grep -v "grep" | wc -l`<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if [ $psNum -ge $MAX_RUN_NUM ]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; then<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep 5<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; done&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />done</p><p style="color: #333333; font-family: tahoma, 宋体; line-height: 22.4px; text-align: justify; background-color: #fafafc;"><br />&nbsp;三.循环控制语句&nbsp;<br />&nbsp; &nbsp; break 命令不执行当前循环体内break下面的语句从当前循环退出.&nbsp;<br />&nbsp; &nbsp; continue 命令是程序在本循体内忽略下面的语句,从循环头开始执行</p><img src ="http://www.cppblog.com/HappySky2046/aggbug/214774.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2017-03-23 17:15 <a href="http://www.cppblog.com/HappySky2046/archive/2017/03/23/214774.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle 学习进阶</title><link>http://www.cppblog.com/HappySky2046/archive/2017/01/11/214584.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Wed, 11 Jan 2017 01:04:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2017/01/11/214584.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/214584.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2017/01/11/214584.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/214584.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/214584.html</trackback:ping><description><![CDATA[学习盖总的文章总结如下<br /><br /><div>一、oracle 基础知识</div><div>1.Oracle Concept</div><div>2.Administrator's Guid</div><div>3.Reference 手册</div><div>4.Backup and Recovery User's Guid&nbsp;</div><div>5.Data Guard Concepts and Administrator</div><div>6.Oracle Clusterware and RAC Administrator 手册</div><div></div><div>二、百科全书/手册</div><div>找 杨长老学习文档。</div><div></div><div>三、有点及面，深入思考的学习方案</div><div>《深入解析Oracle》由点到线再及面的学习， 需要专门的培训和系统的学习。 通过实践的学习和深入的思考 "不患寡，而患不深"，&nbsp;</div><div>遇到问题时，不断深入研究，直到问题的核心本质，这样通过一个案例或实际问题的诊断学习和研究，我们可以带动很多连带知识的学习，</div><div>这样从一个点深入下去就形成一条线,再横向扩展就可以形成知识网。</div><div></div><div>四、严谨与独立思考的素质</div><div>勤奋、严谨、具有钻研精神及独立思考能力。&nbsp;</div><div>《Oracle 数据库性能优化》 &nbsp;兴趣 + 勤奋 + 坚持 + 方法 -&gt; 成功</div><div></div><div>五、DBA生存四大守则</div><div>《深入浅出Oracle》</div><div>1.备份重于一切</div><div>2.三思而后行 think thrice before you act&nbsp;</div><div>3.rm 是恶魔</div><div>4.制定规范(规范开发和系统人员)，不规矩不成方圆。</div><div>可以规避有意和无意的错误操作，建设数据库的风险。</div><img src ="http://www.cppblog.com/HappySky2046/aggbug/214584.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2017-01-11 09:04 <a href="http://www.cppblog.com/HappySky2046/archive/2017/01/11/214584.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>github clone boost 库</title><link>http://www.cppblog.com/HappySky2046/archive/2015/08/16/211574.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Sun, 16 Aug 2015 15:23:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2015/08/16/211574.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/211574.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2015/08/16/211574.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/211574.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/211574.html</trackback:ping><description><![CDATA[&nbsp;<div>1.工具gitsys for windows <br />2.git colne 参考 <br />https://svn.boost.org/trac/boost/wiki/TryModBoost#InstallingModularBoost<br />http://dev.activebasic.com/egtra/2013/12/03/620/</div><div></div><div>&gt;git clone https://github.com/boostorg/boost.git&nbsp; <br />Cloning into 'modular-boost'...<br />Receiving objects:&nbsp;&nbsp; 0% (124/197355), 23<br />remote: Compressing objects: 100% (30/30), done.<br />error: RPC failed; result=56, HTTP code = 200<br />fatal: early EOF<br />fatal: The remote end hung up unexpectedly<br />fatal: index-pack failed</div><div></div><div>Git 遇到了 early EOF index-pack failed 问题 </div><div></div><div># 为 git 添加配置项，通过下面的命令可以简单完成<br /># 在这之前可以执行 git config -l 命令看看已有配置项有哪些<br />git config --add core.compression -1<br />上面是通过命令来完成的，很方便，当然可以直接修改 .gitconfig 文件（在用户目录下），如果你愿意的话。部分内容如下：<br />[user]<br />&nbsp;&nbsp;&nbsp; name = Ggicci<br />&nbsp;&nbsp;&nbsp; email = ...<br />[core]<br />&nbsp;&nbsp;&nbsp; compression = -112345</div><div></div><div>在 [core] 这个 section 里面添加 compression 属性即可。至于它的取值可以参考 Git Config Manpage，<br />这个页面你可以通过 man git config（linux） 或者 git config --help（windows）来查看本地版本。</div><div><strong>compression</strong> 是压缩的意思，从 clone 的终端输出就知道，服务器会压缩目标文件，然后传输到客户端，客户端再解压。取值为 [-1, 9]，-1 以 zlib 为默认压缩库，0 表示不进行压缩，1..9 是压缩速度与最终获得文件大小的不同程度的权衡，数字越大，压缩越慢，当然得到的文件会越小。<br /><div>$ cd boost<br />$ git submodule init<br />$ git submodule update<br />&gt; bootstrap.bat<br />&gt; b2 headers<br />或者 <br />$ git clone --recursive https://github.com/boostorg/boost.git boost<br />&gt; cd boost<br />&gt; bootstrap.bat<br />&gt; b2 headers<br />更换发行版本<br />$ cd boost<br />$ git checkout release-1.55.0<br />$ git submodule update</div></div><img src ="http://www.cppblog.com/HappySky2046/aggbug/211574.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2015-08-16 23:23 <a href="http://www.cppblog.com/HappySky2046/archive/2015/08/16/211574.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>成长、团队、信任</title><link>http://www.cppblog.com/HappySky2046/archive/2014/08/16/208033.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Sat, 16 Aug 2014 07:08:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2014/08/16/208033.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/208033.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2014/08/16/208033.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/208033.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/208033.html</trackback:ping><description><![CDATA[<div><span id="ctl00_MainContentPlaceholder_ctl01_ctl00_lblEntry"><div> <div>很高兴有机会，在这里演讲。我和鲁肃是不太一样的两类人，我是属于意识流派，所以PPT只做了一页。  刚才魏延在介绍鲁肃的时候说，鲁肃象一台不断运转并自我修正的计算机。很多技术人，在不断运转，自我修正真的是一种蛮好的状态。但是我最近，尤其是今年有 些理解，其实做技术，或其它专业，或不做技术做人的工作也好，到最后，核心的，本质的东西，道理上都是相通的。</div> <div>&nbsp;</div> <div>关于成长这个话题，大家可能觉得，象鲁肃这样的人，这几年伴随支付宝成长。但这个成长，每个人怎么看待，大家会经历些什么相似的阶段。不管你是架构的，做开发的，做SA，网络，所有这一切在成长道路上的体验是大体相似的。每个人都会经历这些阶段。我把它总结为三个阶段</div> <div>&nbsp;</div> <div><span style="color: #0000ff;">第一阶：不断学习，学以致用。</span></div> <div>其实我们在这个领域里，或行业里，我们所要不断学习去使用的东西，都有前人在走这样的路。或者在我们身边，已经有人在这样走了，这个时候我们走起来比较痛快，也比较快。这是学以致用的阶段。</div> <div>对我自己来讲，04年3月加入阿里，进入快速学习，使用，学习，使用这样一个循环。其实，这个成长过程，几乎是伴随阿里从只有1千万PV左右的 网站到突破上亿PV，从公司只有1千多人到1万人。因为有很多东西需要我不断去提高我自己，这个阶段中不断在学习，在成长。这个阶段几乎一直进行到06 年，07年。我想，在座各位，绝大部分人仍在进行学以致用这个阶段。</div> <div>&nbsp;</div> <div><span style="color: #0000ff;">第二阶：要靠勇气去承担责任，来突破自我。</span></div> <div>这是什么时候呢？你会发现，你在你的组内或小部门里，或这个领域里，你身边看不到你要学习的对象，也看不到有什么大的方面，技术的东西需要你去 看书，做实验。你很迷惑，很彷徨。这个时候，也许你是P7,P8,P9也可能P10。在这个时候，前面没有榜样，咋办？然后我们所做的事情，开始进入日复 一日，年复一年的阶段。</div> <div>我这个人比较喜欢干一件事，每过一两个月，我会想想我最近在干嘛？我以前在干嘛？我去年在干嘛？如果我发现，我现在跟一年前的我，跟半年前的 我，所作的工作或想法，，没有太大变化的时候，我是很惶恐的。难道我这一生就进入一条直线，再也不会上升了吗？所以说，这个时候，我要想办法做一些事情去 突破我自己。</div> <div>&nbsp;</div> <div><span style="color: #0000ff;">天花板</span></div> <div>以前，我们会想，这些事情嘛，是国外那些大厂家做的。我们也就YY下，哪儿轮得到我们去做呢？但是，在这个阶段，大约07－08，我们做了很多 这方面的尝试，有很多收获，也有郁闷，痛苦，带来错误，带来故障的经验。在这个时期，这么经历下来，我发现其实很多事情，我们在想的东西，我们想去做这个 事情，不是说只有国外大的厂家才能做才能做，我们没有一点都没有机会，没有可能？如果我们自己给自己树了一个天花板，那你永远都在这个天花板下面。</div> <div>&nbsp;</div> <div>我们说，能力有多大，空间有多大，很多时候都是由我们的惯性决定的。我们认为我们只能做这样的事情，我们认为支付宝，阿里巴巴集团的技术，在行业里就是这个水平上了，如果有深刻的先入为主的意识，那这决定我们这群人最终就只能这样。</div> <div>我们要跳出来，站出来去看。其实我们不是说公司客观上没有需要，我们只是努力在拔高自己，其实没有这样。过去两三年，阿里巴巴集团，支付宝这么快速的成长，未来一年，两年，三年，难道我们就只是稳定增长，就不成长了吗？</div> <div>&nbsp;</div> <div>上周郭靖在讲支付宝未来两年的战略，大家想一想，我们期望在2011，有1亿深度活跃会员，有1万亿的交易，这个速度和我们前几年的速度几乎是 差不多的。那我们在现在这个规模下，我们的系统这么复杂，我们的人这么多，其实我们所面临这个挑战比以前更大。更需要我们去成长，但我们却感到了自己的天 花板。</div> <div>&nbsp;</div> <div><span style="color: #0000ff;">勇于突破</span></div> <div>我们要勇于突破自己，有勇气去承担这个责任。这也是我们最近在一些小部门会议讨论的时候发现的事情。大家都发现，看别人部门，都觉得他们部门有 好多事情可以做。那么多的东西，他们的成长轨迹，大家都觉得看得很清楚。为什么那个团队自己的人好像都不知道该干嘛，很迷惑。但是回过来问我们自己部门的 时候，每个人都觉得我们还真不知道怎么去突破，真不知道该干嘛。</div> <div>&nbsp;</div> <div><span style="color: #0000ff;">DBA历程</span></div> <div>刚才魏延说，我们阿里巴巴集团，比如说象DBA这样的群体，从我来的时候7个人，到现在70－80人，为什么这么多人？外界都很疑惑，在质疑。你们招那么多人干嘛？你们就是一个黑洞。大辉来之前说，你们那么多人干嘛还招人，大辉来了后拼命去招人。这都是很真实的体验。</div> <div>&nbsp;</div> <div>其实这就是伴随公司成长的需要，为什么我们需要这么多人？那是因为我们拓宽了DBA这个群体的职责，我们做了很多传统DBA没有做的事情。传统 DBA只要保障好这个生产系统稳定，只要把备份做好就可以了，其它事情一概不管开发部门和他们没有关系。我们没有这么做，我们在朝上往业务靠近，朝下往系 统，向硬件靠近。我们做了很多尝试去拓展这个领域。</div> <div>&nbsp;</div> <div>也是这样，才使得我们需要这么多人。这才使得，象我这样一个做DBA的，能做到P10。这是其中重要的一个因素，另外一个因素，和我待会要谈的 信任有关。我自己的成长能得到公司的认可，也绝不简简单单是因为我的技术很好。如果仅是这么一个因素，你是得不到大家认可的。你技术很好，和其它人有什么 关系？别人凭什么认可你？凭什么接受你？这是我们大家要思考的一个问题。有的人在这条路上走下去，大家说，"这个人技术是挺好的，但这个人嘛，反正我并不 接受他。。。"</div> <div>&nbsp;</div> <div>我们每个人在自己的领域不断突破自己，你会发现，什么天花板都是自己给自己的。空间是自己去突破，自己去创造的。别人光告诉你，上面有好多事情可以做哦，你说"我觉得我做不了，我觉得我们这个团队都做不了"。切记，我希望大家能认真思考下这个问题。</div> <div>&nbsp;</div> <div><span style="color: #0000ff;">影响别人</span></div> <div>当你如果完成了这步突破，接下来你发现一个很糟糕的状况，就是：你属于去说教了，"大家要注意了，要突破自己，其实没有什么是不能做的"。这个时候你开始去游说大家的时候，你发现大家都不响应你，你会发现，你很孤独。</div> <div>因为我们现在的技术领域都是综合性交叉的，越来越复杂，广度越来越大。一个人，两个人都不足以完成很重要的技术的攻关。很多事要靠一群人去做。 当你突破了自己的时候，你很孤独，怎么办？你得要去影响那些可以突破自己的人，你得去影响你身边的人，让他们来跟你一起往前走，让更多的人来突破自己。这 个时候，你可能才不孤独。</div> <div>&nbsp;</div> <div>当有一群人都突破自己，就带动一个氛围，大家一起往前走，进入一个良性的循环。因为突破自己这件事情，我现在突破了自己，可能过两年我又要突破自己。这不是一个自我修正的过程，是一个自我促进，良性循环的过程，往前走的过程。</div> <div>&nbsp;</div> <div>所以说，刚才以前B2B的同事跟我开玩笑说，听说你在支付宝没谈你的技术，就是谈人生，谈理想去了。我说，"是的"。</div> <div>很多时候，我发现再做技术，发现一种无力的感觉。为什么？很多时候，你想做的事情，没有人信啊！或者，没有人愿意把自己投进来。都说，这个事是挺好，他们去做，我还是做我自己的。</div> <div>为什么他们不愿意投进去？我信不信任我自己？我相不相信自己有能力去做这个事情？我相不相信，我有没有可能去突破自己？我有没有可能去完成一件看起来不可能完成的任务。</div> <div>我们敢不敢把自己的青春投进去，可能我们都站在边上犹豫，没有勇气敢去承担这个责任。</div> <div>&nbsp;</div> <div> <p><span style="color: #0000ff;">英雄</span></p> <p>我们经常发现我们总是有很多人在危难之时来力挽狂澜。于是，我们给予这样的人以赞扬。但是，我们反过来想，做技术的人，如果我们总是有人在困境中去 力挽狂澜，那是不是说我们做得不好？做技术的人，实际上应该是，我们的系统支持我们的业务，就应该是四平八稳的，能满足业务频繁的变化，极快速的增长。没 有什么危难时机，这才是我们要追求的境界。<br />但为什么总频频出现危难关头有个英雄人物出来？因为在危难关头，被推到风尖浪口的人，他是不需要勇气，不需要责任的。这件事情，如果我做好了，我是万众瞩目的；如果我没做好，放眼望去，谁能做？这是情势所逼嘛，我是被推上去的。</p> <p>中学时学历史，说什么武昌起义，黎元洪被推上了领袖的位置，黎元洪说了句"莫害我"。这是历史书上的原话。也许我们不敢说"莫害我"，但我也只有咬 着牙上。但是我心里很坦然，我唯有全力朝前走，才有可能攻下这个难关，才有可能力挽狂澜。我心里没有负担，因为此时此刻，非我莫属。虽然我是被逼的，我是 被成长的。<br />久而久之，是不是大家习惯了做这样的英雄。我们能不能在危难来临之前，我们有勇气走出去，去扛起这个责任。这两者只是时间上有差异，但本质上对我们个人的突破是相当不一样的。你突破的是自我，是自己的心里障碍。不简简单单是技术能力的问题。<br />如果你能在这一刻走出来，完成技术的提升，那么接下来你的路会越走越顺。你就不会等着在风尖浪口上再出来。我们整体，做技术人和系统才能稍微领前一步业务的发展。</p> <p><span style="color: #0000ff;">送死你去，背黑锅我来</span></p> <p>不信自己，不敢，这是我们一个很大的麻烦。尤其我们怕说，我去做，做错了怎么办？做砸了怎么办？多做多错，少作少错。首先，做运维的，少作系统少出问题，反正不做，那个系统出了问题没有什么责任，做了出了问题，可能一堆人指着你说"看，做砸了吧。"<br />我们有没有这个勇气？我们所有人在看待别人的时候，也要以一个平和的，能取理解这个事情的角度上去看。其实我们都是在错误中成长的，我们应该鼓励他，支持他，说"兄弟，你上，有问题我们一起扛着。"</p> <p>作为我们的主管们，以前有句话叫"送死你去，背黑锅我来"。因为要去承担责任，你有可能牺牲，有可能出问题，对不对？但是这个黑锅我替你背了，或者我跟你一起背了。我做不了这个事情，你做得了，那你就勇敢的去上。不要担心后顾之忧，不要想着你往前一站，后面的人往后一退。<br />这个时候，我们如果养起这样一个习惯。这是无形的，不是我们哪个人愿意。一谈起来，我们都觉得这样不对，但做起来就身不由己都成了这样了。这是我们人和人之间的问题。</p> <p><span style="color: #0000ff;">攻坚战</span></p> <p>支付宝有这么多长远的理想，要达成这样的目标，就好比打一场攻坚站。</p> <p>我们一起往前冲，地上可能有陷阱，前方还有子弹，我们怎么冲锋？怎么打？开始在那里讨价还价，观望，我这个组等那个组往前走了，没有危险了，我再跟上。</p> <p>前面哪里有敌人在扫射，等他们先去暴露，我再跟上，是吧？每个人开始都害怕，都等着别人先上，都在看一步走一步。实际上，我们把打仗的时间浪费掉了，这是第一个。</p> <p>第二个，谁都不愿意上，唯唯嗦嗦的，敌人正好剿灭我们。理想的状态是什么？我们每个人，每个团队尽全力，一起往前冲，在这个过程中发现不足的地方，发现阵型有缺陷的地方，勇敢去补上。在这样一种氛围下，才可能支撑我们支付宝业务快速的发展。</p> <p>我们现在这个支付市场，我们觉得自己占的份额过半，但是这个领域还处于快速成长的初级阶段，未来的市场还有这么大。即时我们以稳定的速度发展，但是外面那块快速成长的市场难道我们就不要了吗？如果我们自己获得不了的话，那别人就一定会起来。有这个需要，就一定有市场起来。</p> <p><span style="color: #0000ff;">信任</span><br />所以说，在这个过程中，人和人之间做事 情，大家要坦诚一点，彼此要信任。一件事情，我最大能使力到什么程度，尽快的把它表达出来，大家做一个合理的，理性的选择。不要说其实我可以使这么大力， 但是我先说，我可以做到这里。等你看，要是你能补一下，这件事情也可以做完，那OK，就这样做了。但是你要知道，你只使这么大力，你可能只花很少的一部分 精力，时间。但是别人为了弥补，做了很多憋屈的事情，甚至奇奇怪怪的系统的架构，投入了很多资源才能做好这件事。这对我们整体资源是一个浪费。<br />坦诚<br />我 们怕不怕今天我多做了，明天我会做得更多？这已经不是多做多错的问题，而是你多往前走一步，伙伴往后退一步。你怀着对公司的梦想和使命，为了公司的理想你 再往前走一步，伙伴们又往后退一步，你会觉得心里麻凉麻凉的。那这个时候怎么办？其实我们应该很坦诚的表达出来，一件事情该怎么做，彼此间该怎么配合，其 实有一个比较客观的，理性的选择。只要大家坦诚，大家都是能明白的。</p> <p><span style="color: #0000ff;">池塘</span><br />其实我们彼此之间是没有本质利益冲突的。 站在公司发展的立场上，我们都是一样的，所有技术人员，所有的主管，我们的方向都应该是一样的。如果在一个平稳的公司，这个行业已经成熟，那你多做一些事 情，可能就使得别人少作一些事情。因为这个公司已经成熟了，已经不发展了。你多做了就必然是别人少作了，你多做了会给别人造成生存危机，他就没事可做了， 他就不知道自己的价值。那你要多做，别人就觉得你在抢他饭碗。这是在一个成熟的公司，可能会有这样一个矛盾。</p> <p>但是我们现在没有啊，外面还有那么大的空间，给我们每个人，每个部门提供了那么大的空间，可以去做，可以去成长。我们的人员规模还在高速的发展中。我们需要每个人使出全力。才有可能支持我们公司在这个市场上去获取更大的份额，去交出更漂亮的成绩来。</p> <p>&nbsp;但是如果我们在内部就开始做事情在等待，不主动，甚至在博弈，甚至在讨价还价。我讨价还价，我的底牌是不轻易亮出来的。如果都处于这么一个阶段，这么一个状况，将严重阻碍公司的发展。</p> <p>公司就像一个大的池塘，，每个部门就像一个小的池塘，这个池塘不变大，怎么养得出大的鱼来？我们怎么成长？我们每个人都希望从小鱼长成大鱼，但是如果池塘都这么小，你长不出来的。</p> <p>所以说，我们要齐心协力。人和人之间坦诚相待，加强信任，一起往前走。</p> <p><span style="color: #0000ff;">谈事？谈感情？</span><br />包括我们团队成员跟我们的主管之间，其实这类事情，给我们主管提出很高的要求。你既要在技术方面要有感觉，也许不是最精通的，但要有感觉；在对人方面的专注要加强。</p> <p>我一直在提倡说，周会的时候，我们多一些对事的看法，对人的看法的交流。如果我们所有的工作，所有场合中，我们都是在谈事情，这个事情该怎么做，这 个业务该怎么完成，我们进度是多少。每天只谈这些事情，最后发现，我们跟主管之间，我们每个人之间，都是以事情为纽带，我们人和人之间是没有纽带这个概念 的。我们不是一个整体。这样子，我们就难以发挥我们整体的战斗力。</p> <p><span style="color: #0000ff;">揣摩 信任</span></p> <p>然后，当别人提出一个什么想法，想做什么事情，或者，要发表一个观点的时候，就有可能这样一种情况"咋回事？他是不是不想干了？想我干了？"。然后，就可能进入一个揣摩的状态，这个人在想啥呢？</p> <p>如果我们人和人之间能建立起信任的关系，即时他提出来这件事情要我去做，我也基于对人的信任，我觉得他提出来，肯定是对公司有利，肯定是对部门有 利，肯定是应该的，要去做的。那我就全力上去支持他，大家一起把事情做好。我不需要去等待，我只需要去拥抱，去理解。不需要这么多琢磨。</p> <p>我不希望，我们在说很多话的时候，前面要说3，5句话做铺垫，这个现象也是我们团队中存在的。我们发现，当一个人讲一句话，有可能给其它人带来困扰 时，大家说这句话之前，要说几句话铺垫。说："我想讲一句话，其实不是针对你们谁谁谁。。。"一通罗列完后，说"这件事，是这样子的。。。"才开始进入正 题。</p> <p>我难以想象，难道我们真的就这么脆弱，难道一句话，一件事情到底它是不是对的，是不是有道理的，我们就没有真正的分辨能力吗？难道我们就没有办法建立信任关系，让彼此之间没有那么多阻挠，想说就说。</p> <p>所以所有的事情，都是讲我们怎么做，什么样的事情有什么样的价值，而不存在对某个人有什么抵触，有什么抗拒。这种情况我看到不少，我觉得我们在这方面，应该去思索，去改进。</p> <p><span style="color: #0000ff;">一视同仁</span><br />我在B2B工作了几年，什么荣誉也 好，别人叫我什么称号也好，我都不觉得这个是什么。但是，有个人有一次，他还不是技术部的，那个人跟我一点都不熟，他说了一句话，让我很感动。他说"我们 觉得你对所有的人，做任何事情的要求是平等的。从来不看我们是一个小P还是一个大P。我们真的觉得你没有区别对待，我们觉得你对大家是一视同仁的。"<br />他 就说了这么一句话让我很感动，我后来反思自己：我在想什么，我在说什么，我在做什么，我是不是对所有人是一样的？我是不是看人做事？我是不是因为这个人跟 我关系好我就多支持他一点？那个人跟我关系一般，我的资源，我的时间就少向他支持一点？我是不是在这样的原则下做事情？这很重要。<br />你是否能赢得别人的信任，很多时候，就决定于你自己。你是否信任别人？你是否能一视同仁？你是否能一如既往的，对所有人表达一种声音，一种态度？这真的很重要，这是你能赢得别人尊重的前提。</p> <p>我们很多时候在抱怨，做事情成功的可能性跟我们在公司里边，跟各个部门的关系成正相关。这是不是我们很多人一个很深刻的感受？不光支付宝，包括B2B，大家都有这个声音，在表达，在说。这样合不合理？该不该？我觉得我们都需要反思这个问题。<br />我 也不指望今天我提出这个话题后，大家就变了。但是我希望我们的人，是不是应该去反思这个问题，我们尝试去改变。这个改变不是说M要做事情去改变，要从每个 人做起，从自己做起。如果觉得这个是对的，那就这样去做，不需要等待。在这样一个过程中，我们就能赢得别人的信任，建立起信任。</p> <p><span style="color: #0000ff;">孙子和大爷</span><br />很多时候，我也在不同的场合听到，大家做事情的时候，包括运维部，包括架构部，都听到这样一种声音"做点事情真难啊！不光是要有关系啊！对公司这么好的一件事情，这么有价值的一件事情，我到处求爷爷，告奶奶，我真他妈跟孙子似的。"。都觉得自己是孙子。<br />但是反过来一看呢，我觉得我们公司，架构部还算推行比较容易的部门，很强有力的部门，还觉得自己是孙子。可能在另外的部门就觉得，这个玩意儿就跟大爷似的。我觉得这个很有意思，我们每个人都觉得自己是孙子，别人都觉得我是大爷。为什么？为什么？真的很有意思。<br />我们想一想，我们做事情，遵循什么规则，什么原则。我们推行跨部门合作，团队和团队之间要合作，到底基于什么根本原则去做。基于一些原则，我们就可以把关系的问题扫清。否则，我们都觉得难啊。<br />现在支付宝300个人，就已经觉得难了。再往下走，下半年要进100多个新生，明年可能还有新生，还有社招，那么多人进来。他们一进来，肯定觉得更难了，是不是？各位在这里什么老油条，老姜们，都觉得做点事情难，他们怎么做？<br />我们每个人，至少想想这个问题。这似乎不是管理手段，政策制度可以解决的问题。我希望每个人能从自己做起，不断去反思这样的事情。不仅人和人，人和主管之间，团队和团队之间，包括我们和公司之间。公司大了，对发展战略的疑惑。</p> <p><span style="color: #0000ff;">开发和PD</span></p> <p>我也会想啊，公司今年做了这样的战略，决定了做什么样的事情。我吭哧吭哧的做完了后情，发现明年这个东西不重要了，不要了，换了个方向去做。我觉得我去年白干了。我辛辛苦苦干出来的东西，最后被抛弃了，很难受。</p> <p>以前我在技术部门，尤其跟产品设计，跟PD，大家换个位置来想这个问题。执行其实是最简单最容易的。做决定比执行难得多。做选择，做决定，要做什么样的产品，达到什么样的目标，远比技术要更困难。<br />前 几天我听说，B2B产品部的人邀请技术部的人，见证了产品的讨论过程。技术部的人最后说："PD这帮人还是蛮优秀的，蛮有能力的。"但以前他们怎么看呢， 他们说"这帮人都他们瞎搞，瞎想！"因为我们不理解，不理解的前提是不了解，彼此之间信息不对称。我们都觉得别人是傻子，就我聪明。</p> <p><span style="color: #0000ff;">公司战略</span><br />回过来，那公司大的方向，战略。你 看，郭靖又在瞎想。今年白搞了，明年又来过。把你放在那个位置，你去试试看。每个公司高速发展中，他的路径都是很曲折的，一定是没有先例可循的。如果一条 道路是固定的，可以追寻的，可以遵循一种模式走成功的。那么我们问，要成功，剩下的是什么？剩下的就是人加资金。只要人加资金投到这里头，遵循这个路径， 就成功了吗？不可能的。创业的公司成千上万，成功的有几家？他们为什么成功？</p> <p>当这些公司成功了，我们说他走出一条什么模式，我们说IBM模式，华为模式，现在外面有人在研究阿里巴巴模式。但是，大家说，这个道路难道先前有谁能看得明白吗？马云能看明白吗？根本看不明白的。<br />所谓战略，是在不断的试错过程中能快速的纠错，我们要有这个能力，能不断的试错，快速的纠错。然后我们的人心要不散，还能一起往前走。<br />前 几天，我跟人闲聊的时候说，百度在做有啊，做百付宝，那么容易成功吗？微软这么大家公司，做互联网，从跟网景互斗开始，这么多年，为什么在互联网领域就做 不成？是因为他没钱吗？没人吗？都不是。要做成一件事情，能有一股力量，能让大家方向一致，拧成一股绳往前走，这是相当困难的。<br />对于我们集团来 讲，我个人的理解，有的人是有共同的信仰或信念，有他的使命。但是我们大部人，真的是能切身感受到这个使命吗？这是不一定的。但有一点，我们相信公司，我 们相信马云，信他。就跟着他怎么说，就怎么走了。即时错了，带我们调整方向，调整路径，最终我们走了十年。未来再走的话，我们还要遵循这个原则一直往前 走。<br />这个过程，我们付出的代价就是我们很苦闷的东西，去年白干了。过去曾经是重点的项目，重点的产品，现在不再是重点了，换了方向了，这就是成长过程付出的代价。但是不能因此就觉得那帮领导就是天马行空，一帮猪脑子。<br />也许我们觉得自己很聪明，但是我深深的感受到，我们都不智慧。聪明和智慧真的是两件事。</p> <p><span style="color: #0000ff;">总结</span><br />我们做技术的人学以致用，勇于承担，去突 破自我去影响他人。包括其它人，包括马云，包括虚竹，他要影响，也都是这样一个过程。每个领域都是这样一个过程。从这个角度讲，都是相通的。他要完成他应 该的使命，他也需要我们去突破自己。所以说，这所有的一切，都能找到一个共性的东西。<br />我希望我们能来严肃的，认真的思考一下这个问题。想想我们每 个人该怎么做，不要等，不要等政策，不要等主管。每个人从我做起，从现在做起。做你觉得你想做的，然后把你觉得你想做的东西多跟其它人交流。看看我自己想 做的东西是不是有偏差，是不是可能不太合理？多跟别人碰撞，多跟不同的人交流，你会发现，其实每个人，形形色色的想法，一是很有意思，二是在这个过程中， 你可以去总结，去归纳，去提炼，可以得到升华。<br />所以说，我给自己找点理由。要谈人生，谈理想，其实背后的本质是这样的：我希望看到大家是怎么思考问题的，为什么我们每个人有每个人的标准，还深以为然，但是别人却不那么认可你。我们怎么样突破这个困境？这就是我为什么要谈信任这个话题。<br />因为我觉得，这件事情不解决，我们招再多的人，也被我们低下的效率研磨掉了，人越多越臃肿，这是我们必须解决的问题，这样我们才能支持公司健康的往前走。我讲完了，谢谢大家。</p></div></div></span></div><img src ="http://www.cppblog.com/HappySky2046/aggbug/208033.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2014-08-16 15:08 <a href="http://www.cppblog.com/HappySky2046/archive/2014/08/16/208033.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式六大原则 </title><link>http://www.cppblog.com/HappySky2046/archive/2014/05/28/207125.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Wed, 28 May 2014 01:41:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2014/05/28/207125.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/207125.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2014/05/28/207125.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/207125.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/207125.html</trackback:ping><description><![CDATA[<div><p> <span style="font-size: 18px; ">1、单一职责原则（Single Responsibility Principle，简称SRP）<br />  &nbsp; &nbsp; &nbsp;  单一职责原则，就一个类而言，应该仅有一个引起它变化的原因。如果一个类承担的职责过多，就等于把这些职责耦合在一起，一个职责的变化可能会消弱或者一直 这个类完成其他职责的能力。这种耦合会导致脆弱的设计，当变化发生时，设计会遭受到意想不到的破坏。而软件设计真正要做的许多内容，就是发现职责，并把这 些职责相互分离。</span></p> <br /> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; "> <span style="font-size: 18px; ">&nbsp; &nbsp; &nbsp; 一句话点评：高内聚低耦合的绝佳体现，不要乱拉关系，独善其身挺好。</span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; "> &nbsp;</p> <p> <span style="font-size: 18px; ">2、 开放--封闭原则（The Open-Closed Principle简称OCP）<br />  &nbsp; &nbsp; &nbsp; &nbsp;开放--封闭原则，是说软件实体（类、模块、函数等等）应该可以扩展，但是不可以修改。即对于扩展是开放的，对于更改是封闭的。  我们不可能做到未卜先知，在设计的时候尽可能让一个类足够好，设计好了就不要去修改了；不能完全封闭的情况下，当发生变化时，我们就创建抽象来隔离以后发 生的同类变化。</span></p> <br /> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; "> <span style="font-size: 18px; ">&nbsp; &nbsp; &nbsp; 一句话点评：开放扩展，封闭更改，开合有度是一门艺术。</span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; "> &nbsp;</p> <p> <span style="font-size: 18px; ">3、依赖倒转原则（Dependence Inversion Principle ）<br />  &nbsp; &nbsp; &nbsp;  依赖倒转原则，指高层模块不应该依赖低层模块，两个都应该依赖抽象；抽象不应该依赖细节，细节应该依赖抽象。说白了就是要针对接口编程，不要对实现编程。 举个例子：计算机硬件中，如果内存坏了，那么只需要换一个内存条就可以了，而不需要去换一个主板，在这里内存是一个接口类，只要符合他的规格要求就行，无 论是那一根。</span></p> <br /> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; "> <span style="font-size: 18px; ">&nbsp; &nbsp; &nbsp;一句话点评：搞建筑时要做设计师，而不是砖瓦工，抽象的蓝图要靠具体的材料一点点实现。</span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; "> &nbsp;</p> <p> <span style="font-size: 18px; ">4、里氏代换原则（Liskov Substitution Principle，简称LSP）<br /> &nbsp; &nbsp; &nbsp;里氏代换原则，子类型必须能够替换掉他们的父类型。在软件里面，把父类都替换成其子类，程序的行为不会发生变化。正是由于子类型的可替换性才使得使用父类型的模块在无需修改的情况下就可以扩展。</span></p> <br /> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; "> <span style="font-size: 18px; ">&nbsp; &nbsp; &nbsp;一句话点评：长辈给了你继承的权利就一定要做赡养的义务，把长辈的职责都要承担起来。</span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; "> &nbsp;</p> <p> <span style="font-size: 18px; ">5、迪米特法则（<span style="font-family: arial 宋体 sans-serif; font-size: 15px; line-height: 24px; ">Law of Demeter</span>）<br /> &nbsp; &nbsp; &nbsp;&nbsp;<span style="font-size: 18px; ">迪米特法则，</span>如 果两个类不必彼此直接通信，那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法时，可以通过第三者转发这个调用。类之 间的耦合越弱，就越有利于复用，一个处在弱耦合的类被修改，不会对有关系的类造成波及。 主要是强调了类之间的松耦合。</span></p> <br /> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; "> <span style="font-size: 18px; ">&nbsp; &nbsp; &nbsp;一句话点评：不要和陌生人说话，若两国交战要尽量避免正面冲突，多派使者协商调度。</span></p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; "> &nbsp;</p> <p> <span style="font-size: 18px; ">6、合成/聚合复用原则（Composition/Aggregation Principle]，简称CARP）<br />  &nbsp; &nbsp; &nbsp;合成聚合复用原则，尽量使用合成/聚合，尽量不使用类继承。合成聚合是&#8220;has &nbsp;a&#8221;的关系，而继承是&#8220;is  &nbsp;a&#8221;的关系。由于继承是一中强耦合的结构，父类变，子类必变。所以不是&#8220;is&nbsp;  a&#8221;关系，我们一般不要用继承。优先使用合成聚合复用原则，有助于保持每个类的封装，降低继承的层次。<br /> &nbsp; &nbsp; &nbsp;一句话点评：优生优育，不要盲目繁衍。</span></p></div><img src ="http://www.cppblog.com/HappySky2046/aggbug/207125.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2014-05-28 09:41 <a href="http://www.cppblog.com/HappySky2046/archive/2014/05/28/207125.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Component Object Framework</title><link>http://www.cppblog.com/HappySky2046/archive/2013/12/25/205003.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Wed, 25 Dec 2013 03:19:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2013/12/25/205003.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/205003.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2013/12/25/205003.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/205003.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/205003.html</trackback:ping><description><![CDATA[&nbsp; &nbsp;基于组件开发的模型有一下方案：<br />&nbsp; &nbsp;1.微软的COM<br />&nbsp; &nbsp;2.<a href="https://developer.mozilla.org/en/XPCOM_API_Reference" rel="nofollow" style="font-family: Simsun; font-size: medium; line-height: normal;">XPCOM</a>&nbsp;<br />&nbsp; &nbsp;3.<a href="http://www.freedesktop.org/wiki/Software/dbus" rel="nofollow" style="font-family: Simsun; font-size: medium; line-height: normal;">DBus</a><br />&nbsp; &nbsp;4.&nbsp;<a href="http://api.kde.org/3.5-api/kdelibs-apidocs/dcop/html/index.html" rel="nofollow" style="font-family: Simsun; font-size: medium; line-height: normal;">DCOP</a><br /><font size="3">&nbsp; &nbsp;5.</font><a href="http://www.osgi.org/About/WhatIsOSGi" rel="nofollow" style="font-family: Simsun; font-size: medium; line-height: normal;">OSGi</a><img src ="http://www.cppblog.com/HappySky2046/aggbug/205003.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2013-12-25 11:19 <a href="http://www.cppblog.com/HappySky2046/archive/2013/12/25/205003.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>bjam 参数</title><link>http://www.cppblog.com/HappySky2046/archive/2013/12/14/204794.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Sat, 14 Dec 2013 02:36:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2013/12/14/204794.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/204794.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2013/12/14/204794.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/204794.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/204794.html</trackback:ping><description><![CDATA[<p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;"><br />典型的参数<br />bjam --toolset=msvc-8.0 --with-date_time --with-thread &nbsp;--link=static --threading=multi --runtime-link=shared debug stage</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">为了方便，你还可以这样：</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">bjam --with-date_time --build-type=complete --toolset=msvc-8.0 stage</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">注意，--build-type=complete表示生成debug release static shared的各种版本</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">还有一个非常需要注意的地方，我在一次编译的时候遇见过很变态的问题，由于安装了VS2008，所以我想用VC9来编译，结果VC9的设置似乎与环境变量冲突，在打开命令行工具的时候会提示：此时不应有：&lt;此处为系统的所有环境变量&gt;。这个奇怪的问题很可能是由于环境变量里的路径过长或包含不该有的符号而导致的，但奇怪的是，VS2005并没有这个冲突问题。所以，这时候如果要编译boost的话只有两条路走：1、搞定VS2008的冲突，重装环境变量里路径过长的程序。2、用VS2005的命令行工具去编译。顺带一提的是，这时候最好不要用系统中的cmd，而是在开始-&gt;程序-&gt;VS2005-&gt;工具-&gt;命令提示里执行bjam的工作。</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">其他参考：</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">bjam参数 --build-dir=&lt;builddir&gt; 编译的临时文件会放在builddir里(这样比较好管理，编译完就可以把它删除了)&nbsp;<br />--stagedir=&lt;stagedir&gt; 存放编译后库文件的路径，默认是stage&nbsp;<br />--build-type=complete 编译所有版本，不然只会编译一小部分版本（确切地说是相当于:variant=release, threading=multi;link=shared|static;runtime-link=shared）&nbsp;<br />variant=debug|release 决定编译什么版本(Debug or Release?)&nbsp;<br />link=static|shared 决定使用静态库还是动态库。&nbsp;<br />threading=single|multi 决定使用单线程还是多线程库。&nbsp;<br />runtime-link=static|shared 决定是静态还是动态链接C/C++标准库。&nbsp;<br />--with-&lt;library&gt; 只编译指定的库，如输入--with-regex就只编译regex库了。&nbsp;<br />--show-libraries 显示需要编译的库名称<br /></p><p class="MsoNormal" align="left" style="line-height: 15.75pt; background-color: #faf7ef; background-position: initial initial; background-repeat: initial initial;"><span style="mso-bidi-font-size:
10.5pt;font-family:宋体;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;
mso-bidi-font-family:宋体;color:blue;mso-font-kerning:0pt">以</span><span lang="EN-US" style="mso-bidi-font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;
mso-fareast-font-family:宋体;mso-bidi-font-family:宋体;color:blue;mso-font-kerning:
0pt"> libboost_regex-vc71-mt-d-1_34.lib </span><span style="mso-bidi-font-size:
10.5pt;font-family:宋体;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;
mso-bidi-font-family:宋体;color:blue;mso-font-kerning:0pt">为例：</span><span lang="EN-US" style="mso-bidi-font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;
mso-fareast-font-family:宋体;mso-bidi-font-family:宋体;color:#393939;mso-font-kerning:
0pt"><o:p></o:p></span></p><p align="left" style="margin-left: 33.75pt; text-indent: -18pt; line-height: 15.75pt; background-color: #faf7ef; word-break: break-all; background-position: initial initial; background-repeat: initial initial;"><span style="font-size:10.0pt;font-family:Symbol;color:#393939;">&#183;<span style="font-size: 7pt; line-height: normal; font-family: 'Times New Roman';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style=" font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">lib</span>&nbsp;<span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;"><br /> </span><span style="font-family:宋体;color:blue;">前缀：除了</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">Microsoft Windows</span><span style="font-family:宋体;color:blue;">之外，每一个</span><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color:blue;">Boost</span><span style="font-family:宋体;color:blue;">库的名字都以此字符串开始。在</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">Windows</span><span style="font-family:宋体;color:blue;">上，只有普通的静态库使用</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">lib</span><span style="font-family:宋体;color:blue;">前缀；导入库和</span><span style=" font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">DLL</span><span style="font-family:宋体;color:blue;">不使用。</span></p>  <p align="left" style="margin-left: 33.75pt; text-indent: -18pt; line-height: 15.75pt; background-color: #faf7ef; word-break: break-all; background-position: initial initial; background-repeat: initial initial;"><span style="font-size:10.0pt;font-family:Symbol;color:#393939;">&#183;<span style="font-size: 7pt; line-height: normal; font-family: 'Times New Roman';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style=" font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">boost_regex</span>&nbsp;<span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;"><br /> </span><span style="font-family:宋体;color:blue;">库名称：所有</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">boost</span><span style="font-family:宋体;color:blue;">库名文件以</span><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color:blue;">boost_</span><span style="font-family:宋体;color:blue;">开头。</span></p>  <p align="left" style="margin-left: 33.75pt; text-indent: -18pt; line-height: 15.75pt; background-color: #faf7ef; word-break: break-all; background-position: initial initial; background-repeat: initial initial;"><span style="font-size:10.0pt;font-family:Symbol;color:#393939;">&#183;<span style="font-size: 7pt; line-height: normal; font-family: 'Times New Roman';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style=" font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">-vc71</span>&nbsp;<span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;"><br /> Toolset </span><span style="font-family:宋体;color:blue;">标记：标识了构建该库所用的</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">toolset</span><span style="font-family:宋体;color:blue;">和版本。</span></p>  <p align="left" style="margin-left: 33.75pt; text-indent: -18pt; line-height: 15.75pt; background-color: #faf7ef; word-break: break-all; background-position: initial initial; background-repeat: initial initial;"><span style="font-size:10.0pt;font-family:Symbol;color:#393939;">&#183;<span style="font-size: 7pt; line-height: normal; font-family: 'Times New Roman';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style=" font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">-mt</span>&nbsp;<span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;"><br /> Threading </span><span style="font-family:宋体;color:blue;">标记：标识构建该库启用了多线程支持。不支持多线程的库没有</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">-mt</span><span style="font-family:宋体;color:blue;">。</span></p>  <p align="left" style="margin-left: 33.75pt; text-indent: -18pt; line-height: 15.75pt; background-color: #faf7ef; word-break: break-all; background-position: initial initial; background-repeat: initial initial;"><span style="font-size:10.0pt;font-family:Symbol;color:#393939;">&#183;<span style="font-size: 7pt; line-height: normal; font-family: 'Times New Roman';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style=" font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">-d</span>&nbsp;<span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;"><br /> ABI</span><span style="font-family:宋体;color:blue;">标记：编码了影响库和其他编译代码交互的细节。对于每一种特性，向标记中添加一个字母：</span>&nbsp;</p>  <table border="1" cellspacing="0" cellpadding="0" width="400" style="width: 300pt; margin-left: 33.75pt; border-collapse: collapse; border: none;">  <tbody><tr>   <td width="76" valign="top" style="width: 57pt; border: 1pt solid silver; padding: 2.25pt;">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;   color:blue;">Key</span></p>   </td>   <td width="321" valign="top" style="width: 240.75pt; border-style: solid solid solid none; border-top-color: silver; border-right-color: silver; border-bottom-color: silver; border-top-width: 1pt; border-right-width: 1pt; border-bottom-width: 1pt; padding: 2.25pt;">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;   color:blue;">Use this library when:</span></p>   </td>  </tr>  <tr>   <td width="76" valign="top" style="width: 57pt; border-style: none solid solid; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 2.25pt;">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;   color:blue;">s</span></p>   </td>   <td width="321" valign="top" style="width:240.75pt;border-top:none;border-left:   none;border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;color:blue;">静态链接到C++标准库和编译器运行时支撑库</span></p>   </td>  </tr>  <tr>   <td width="76" valign="top" style="width: 57pt; border-style: none solid solid; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 2.25pt;">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;   color:blue;">g</span></p>   </td>   <td width="321" valign="top" style="width:240.75pt;border-top:none;border-left:   none;border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;color:blue;">使用标准库和运行时支撑库的调试版本</span></p>   </td>  </tr>  <tr>   <td width="76" valign="top" style="width: 57pt; border-style: none solid solid; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 2.25pt;">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;   color:blue;">y</span></p>   </td>   <td width="321" valign="top" style="width:240.75pt;border-top:none;border-left:   none;border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;color:blue;">使用Python的特殊调试构建</span></p>   </td>  </tr>  <tr>   <td width="76" valign="top" style="width: 57pt; border-style: none solid solid; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 2.25pt;">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;   color:blue;">d</span></p>   </td>   <td width="321" valign="top" style="width:240.75pt;border-top:none;border-left:   none;border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;color:blue;">构建代码的调试版本</span></p>   </td>  </tr>  <tr>   <td width="76" valign="top" style="width: 57pt; border-style: none solid solid; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 2.25pt;">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;   color:blue;">p</span></p>   </td>   <td width="321" valign="top" style="width:240.75pt;border-top:none;border-left:   none;border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;color:blue;">使用STLPort标准库而不是编译器提供的默认库</span></p>   </td>  </tr>  <tr>   <td width="76" valign="top" style="width: 57pt; border-style: none solid solid; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 2.25pt;">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;   color:blue;">n</span></p>   </td>   <td width="321" valign="top" style="width:240.75pt;border-top:none;border-left:   none;border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left"><span style="font-size:12.0pt;font-family:宋体;color:blue;">使用STLPort已被弃用的&#8220;native   iostreams&#8221;</span></p>   </td>  </tr> </tbody></table>  <p align="left" style="margin-left: 33.75pt; text-indent: -18pt; line-height: 15.75pt; background-color: #faf7ef; word-break: break-all; background-position: initial initial; background-repeat: initial initial;"><span style="font-size:10.0pt;font-family:Symbol;color:#393939;">&#183;<span style="font-size: 7pt; line-height: normal; font-family: 'Times New Roman';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style=" font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">-1_34</span>&nbsp;<span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;"><br /> </span><span style="font-family:宋体;color:blue;">版本标记：完整的</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">Boost</span><span style="font-family:宋体;color:blue;">发布号，下划线代替点。例如，</span><span style=" font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">1.31.1</span><span style="font-family:宋体;color:blue;">版本将被标记为</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">&#8220;-1_31_1&#8221;</span><span style="font-family:宋体;color:blue;">。</span></p>  <p align="left" style="margin-left: 33.75pt; text-indent: -18pt; line-height: 15.75pt; background-color: #faf7ef; word-break: break-all; background-position: initial initial; background-repeat: initial initial;"><span style="font-size:10.0pt;font-family:Symbol;color:#393939;">&#183;<span style="font-size: 7pt; line-height: normal; font-family: 'Times New Roman';">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style=" font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">.lib</span>&nbsp;<span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;"><br /> </span><span style="font-family:宋体;color:blue;">扩展名：取决于操作系统。在大多数</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">unix</span><span style="font-family:宋体;color:blue;">平台上，</span><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color:blue;">.a</span><span style=" font-family:宋体;color:blue;">是静态库，</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">.so</span><span style="font-family:宋体;color:blue;">是共享库。在</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">Windows</span><span style="font-family:宋体;color:blue;">上，</span><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color:blue;">.dll</span><span style="font-family:宋体;color:blue;">表示共享库，</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:blue;">.lib</span><span style="font-family:宋体;color:blue;">是静态或导入库。</span></p>  <p align="left" style="margin: 7.5pt 0cm; line-height: 15.75pt; background-color: #faf7ef; background-position: initial initial; background-repeat: initial initial;">&nbsp;</p>  <p align="left" style="margin: 7.5pt 0cm; line-height: 15.75pt; background-color: #faf7ef; background-position: initial initial; background-repeat: initial initial;"><span style="font-family:宋体;color:#393939;">下表是对</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">Regex</span><span style="font-family:宋体;color:#393939;">库编译后的文件名：</span></p>  <table border="1" cellspacing="0" cellpadding="0" width="829" style="width: 621.75pt; background-color: #faf7ef; border-collapse: collapse; border: none;">  <tbody><tr>   <td width="275" style="width: 206.25pt; border: 1pt solid silver; padding: 2.25pt;">   <p align="left" style="line-height: 15.75pt;"><strong><span style="font-family:宋体;color:#393939;">文件名</span></strong></p>   </td>   <td width="413" style="width: 309.75pt; border-style: solid solid solid none; border-top-color: silver; border-right-color: silver; border-bottom-color: silver; border-top-width: 1pt; border-right-width: 1pt; border-bottom-width: 1pt; padding: 2.25pt;">   <p align="left" style="line-height: 15.75pt;"><strong><span style="font-family:宋体;color:#393939;">含义</span></strong></p>   </td>   <td width="140" style="width: 105pt; border-style: solid solid solid none; border-top-color: silver; border-right-color: silver; border-bottom-color: silver; border-top-width: 1pt; border-right-width: 1pt; border-bottom-width: 1pt; padding: 2.25pt;">   <p align="left" style="line-height: 15.75pt;"><strong><span style="font-family:宋体;color:#393939;">编译使用该库的程序时应使用的编译选项</span></strong></p>   </td>  </tr>  <tr>   <td width="274" style="width: 205.5pt; border-style: none solid solid; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 2.25pt;">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">libboost_regex-vc90-mt-sgd-1_38.lib</span></p>   </td>   <td width="413" style="width:309.75pt;border-top:none;border-left:none;   border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:宋体;color:#393939;">静态库，多线程，调试版本</span>&nbsp;<span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;"><br />   </span><span style="font-family:宋体;color:#393939;">使用静态调试版本</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">C</span><span style="font-family:宋体;color:#393939;">运行时库（</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">LIBCMTD.LIB</span><span style="font-family:宋体;color:#393939;">和</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">LIBCPMTD.LIB</span><span style="font-family:宋体;color:#393939;">）</span></p>   </td>   <td width="140" style="width:105.0pt;border-top:none;border-left:none;   border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">/MTd</span></p>   </td>  </tr>  <tr>   <td width="274" style="width: 205.5pt; border-style: none solid solid; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 2.25pt;">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">libboost_regex-vc90-mt-s-1_38.lib</span></p>   </td>   <td width="413" style="width:309.75pt;border-top:none;border-left:none;   border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:宋体;color:#393939;">静态库，多线程</span>&nbsp;<span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;"><br />   </span><span style="font-family:宋体;color:#393939;">使用静态版本</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">C</span><span style="font-family:宋体;color:#393939;">运行时库（</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">LIBCMT.LIB</span><span style="font-family:宋体;color:#393939;">和</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">LIBCPMT.LIB</span><span style="font-family:宋体;color:#393939;">）</span></p>   </td>   <td width="140" style="width:105.0pt;border-top:none;border-left:none;   border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">/MT</span></p>   </td>  </tr>  <tr>   <td width="274" style="width: 205.5pt; border-style: none solid solid; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 2.25pt;">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">libboost_regex-vc90-mt-gd-1_38.lib</span></p>   </td>   <td width="413" style="width:309.75pt;border-top:none;border-left:none;   border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:宋体;color:#393939;">静态库，多线程，调试版本</span>&nbsp;<span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;"><br />   </span><span style="font-family:宋体;color:#393939;">使用动态调试版本</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">C</span><span style="font-family:宋体;color:#393939;">运行时库（</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">MSVCRTD.LIB</span><span style="font-family:宋体;color:#393939;">和</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">MSVCPRTD.LIB</span><span style="font-family:宋体;color:#393939;">）</span></p>   </td>   <td width="140" style="width:105.0pt;border-top:none;border-left:none;   border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">/MDd</span></p>   </td>  </tr>  <tr>   <td width="273" style="width: 204.75pt; border-style: none solid solid; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 2.25pt;">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">libboost_regex-vc90-mt-1_38.lib</span></p>   </td>   <td width="413" style="width:309.75pt;border-top:none;border-left:none;   border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:宋体;color:#393939;">静态库，多线程</span>&nbsp;<span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;"><br />   </span><span style="font-family:宋体;color:#393939;">使用动态版本</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">C</span><span style="font-family:宋体;color:#393939;">运行时库（</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">MSVCRT.LIB</span><span style="font-family:宋体;color:#393939;">和</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">MSVCPRT.LIB</span><span style="font-family:宋体;color:#393939;">）</span></p>   </td>   <td width="140" style="width:105.0pt;border-top:none;border-left:none;   border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">/MD</span></p>   </td>  </tr>  <tr>   <td width="273" style="width: 204.75pt; border-style: none solid solid; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 2.25pt;">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">boost_regex-vc90-mt-gd-1_38.lib</span></p>   </td>   <td width="413" style="width:309.75pt;border-top:none;border-left:none;   border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:宋体;color:#393939;">导入库（</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">boost_regex-vc90-mt-gd-1_38.dll</span><span style="font-family:宋体;color:#393939;">），多线程，调试版本</span></p>   </td>   <td width="140" style="width:105.0pt;border-top:none;border-left:none;   border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left" style="line-height: 15.75pt;">&nbsp;</p>   </td>  </tr>  <tr>   <td width="273" style="width: 204.75pt; border-style: none solid solid; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 2.25pt;">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">boost_regex-vc90-mt-1_38.lib</span></p>   </td>   <td width="413" style="width:309.75pt;border-top:none;border-left:none;   border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left" style="line-height: 15.75pt;"><span style="   font-family:宋体;color:#393939;">导入库（</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">boost_regex-vc90-mt-1_38.dll</span><span style="   font-family:宋体;color:#393939;">）多线程</span></p>   </td>   <td width="140" style="width:105.0pt;border-top:none;border-left:none;   border-bottom:solid silver 1.0pt;border-right:solid silver 1.0pt;padding:2.25pt 2.25pt 2.25pt 2.25pt">   <p align="left" style="line-height: 15.75pt;">&nbsp;</p>   </td>  </tr> </tbody></table>  <p align="left" style="margin: 7.5pt 0cm; line-height: 15.75pt; background-color: #faf7ef; background-position: initial initial; background-repeat: initial initial;">&nbsp;</p>  <p align="left" style="margin: 7.5pt 0cm; line-height: 15.75pt; background-color: #faf7ef; background-position: initial initial; background-repeat: initial initial;"><span style="font-family:宋体;color:#393939;">需要注意的是，链接时，所使用的</span><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">Regex</span><span style="font-family:宋体;color:#393939;">库文件名必须和编译选项匹配，否则会造成如下链接错误：</span></p>  <p align="left" style="margin: 7.5pt 0cm; line-height: 15.75pt; background-color: #faf7ef; background-position: initial initial; background-repeat: initial initial;"><span style="font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">LINK : warning LNK4098: defaultlib '&#215;&#215;&#215;&#215;&#215;' conflicts with use of other libs; use /NODEFAULTLIB:library</span></p>  <span style="font-size:10.5pt;font-family:宋体;color:#393939;">原因是，当编译时，</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">cl.exe</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">（也就是</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">VC</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">的编译器）会根据上述编译选项在编译成的</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">obj</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">文件中植入相应的</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">defaultlib</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">文件名（使用</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">DUMPBIN /DIRECTIVE ***,lib</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">可以查看），如</span><span style="font-size: 10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">/MT</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">对应的就是</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">LIBCMT.LIB</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">（</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">C</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">）和</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">LIBCPMT.LIB</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">（</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">C++</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">标准库）。当链接器处理该</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">obj</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">文件时，会从文件中取出该</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">defaultlib</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">文件名，将其放在命令行库列表的最后以供使用。对于静态库的处理也是如此，静态库也是由一些</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">obj</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">文件组成的，每个</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">obj</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">文件中也根据当时的编译选项被植入了相应的</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">defaultlib</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">。当链接器处理静态库时，也会将涉及到的</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">obj</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">文件中的</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">defaultlib</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">放在命令行库列表的最后。假设，我们的程序使用</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">/MT</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">编译，那个对应的</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">defaultlib</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">就是</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">LIBCMT.LIB</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">（</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">C</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">）和</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">LIBCPMT.LIB</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">（</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">C++</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">标准库）。而使用的是</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">libboost_regex-vc90-mt-sgd-1_38.lib</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">，它对应的</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">defaultlib</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">就是</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">LIBCMTD.LIB</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">和</span><span style="font-size:10.5pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;color:#393939;">LIBCPMTD.LIB</span><span style="font-size:10.5pt;font-family:宋体;color:#393939;">。链接过程中，链接器会发现采用了不同的运行时库，所以会出现上述错误。</span><br /><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;"><br /><br /><br /><br /></p><img src ="http://www.cppblog.com/HappySky2046/aggbug/204794.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2013-12-14 10:36 <a href="http://www.cppblog.com/HappySky2046/archive/2013/12/14/204794.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>删除.svn文件夹</title><link>http://www.cppblog.com/HappySky2046/archive/2013/10/30/203998.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Wed, 30 Oct 2013 06:28:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2013/10/30/203998.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/203998.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2013/10/30/203998.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/203998.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/203998.html</trackback:ping><description><![CDATA[<p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">注册表方式：<br /></p><div>Windows Registry Editor Version 5.00</div><div>[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\DeleteSVN]</div><div>@="Delete SVN Folders"</div><div>[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\DeleteSVN\command]</div><div>@="cmd.exe /c \"TITLE Removing SVN Folders in %1 &amp;&amp; COLOR 9A &amp;&amp; FOR /r \"%1\" %%f IN (.svn) DO RD /s /q \"%%f\" \""</div><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;"><br />命令解析<br /><br />将下面内容在.txt文件中保存后，将文件名的&#8220;.txt&#8221;改成&#8220;.bat&#8221;，运行即可。</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">@echo off</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;"></p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">for /r %%a in (.) do if exist %%a\.svn rd /s/q %%a\.svn</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;"></p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">pause</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">@echo on</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;"></p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;"></p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">---------------------------------------------------------------------------------------------------</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">for /r %%a in (.) do if exist %%a\.svn rd /s/q %%a\.svn 这个语句句主要的作用是删除该bat所在的当前目录及其子目录中的所有.svn目录</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;"></p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">该语句的解释如下：</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">首先判断是否存在.svn目录，如果存在，不需用户确认就将其删除；否则进行下次循环。</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">for /r %%a in (.) do -----循环判断指定目录及其子目录</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">if exist %%a\.svn rd /s/q %%a\.svn -----这是循环体</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">If exist %%a\.svn------判断是否存在.svn文件夹</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">rd /s/q %%a\.svn ------不用确认，直接删除.svn文件夹<br /><br /><br /></p><img src ="http://www.cppblog.com/HappySky2046/aggbug/203998.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2013-10-30 14:28 <a href="http://www.cppblog.com/HappySky2046/archive/2013/10/30/203998.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LuaJIT之callback要注意的地方</title><link>http://www.cppblog.com/HappySky2046/archive/2013/02/25/198067.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Mon, 25 Feb 2013 12:29:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2013/02/25/198067.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/198067.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2013/02/25/198067.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/198067.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/198067.html</trackback:ping><description><![CDATA[<div>目前应该在LuaJIT的ffi库中避免使用函数指针，使用Lua本身来封装回调函数（如果接口需要），方可获得LuaJIT提供的卓越性能。<br /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal;">尽可能直接使用第三方的C库，使用ffi来访问API，而非去实现一个Lua C Module，这也是LuaJIT官方所推荐的，这会让luaJIT的优化达到极致（C API访问，以及对Lua-C Module里函数访问时的传参，会有不能被LuaJIT编译优化的开销，虽然这个开销对于非频繁调用的内容并不大）</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal;">另外一个原本预期中的好处是，希望这个项目最终能只有Lua代码，以及luajit主程序、编译好的其他库的动态链接版本，便于去修改、发布及调试。只是目前来看完全这么做还是有点困难。但是使用其他callback不那么常见的库可能会相对轻松。</span></div><img src ="http://www.cppblog.com/HappySky2046/aggbug/198067.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2013-02-25 20:29 <a href="http://www.cppblog.com/HappySky2046/archive/2013/02/25/198067.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>远程桌面连接服务器时，键盘不能正常打字</title><link>http://www.cppblog.com/HappySky2046/archive/2013/02/25/198066.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Mon, 25 Feb 2013 12:26:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2013/02/25/198066.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/198066.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2013/02/25/198066.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/198066.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/198066.html</trackback:ping><description><![CDATA[<span style="color: #333333; font-family: monospace; font-size: 14.166666030883789px; line-height: 25.989582061767578px; white-space: pre-wrap; background-color: #ffffff;">这个问题困扰我很久，其实很简单。<br />解决方案：在远程桌面的XP系统，直接按Win键，远程桌面弹出&#8220;开始菜单&#8221;，这样就恢复了。</span><img src ="http://www.cppblog.com/HappySky2046/aggbug/198066.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2013-02-25 20:26 <a href="http://www.cppblog.com/HappySky2046/archive/2013/02/25/198066.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>iconv的用法</title><link>http://www.cppblog.com/HappySky2046/archive/2013/01/20/197426.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Sun, 20 Jan 2013 08:54:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2013/01/20/197426.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/197426.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2013/01/20/197426.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/197426.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/197426.html</trackback:ping><description><![CDATA[<p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 17.27272605895996px; font-size: 12.727272033691406px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #fefef2;">conv命令是用来转换文件的编码方式的（Convert encoding of given files from one encoding to another）<br /><div>　用法： iconv [选项...] [文件...]</div><div>　　Convert encoding of given files from one encoding to another.</div><div>　　输入/输出格式规范：</div><div>　　-f, --from-code=NAME 原始文本编码</div><div>　　-t, --to-code=NAME 输出编码</div><div>　　信息：</div><div>　　-l, --list 列举所有已知的字符集</div><div>　　输出控制：</div><div>　　-c 从输出中忽略无效的字符</div><div>　　-o, --output=FILE 输出文件</div><div>　　-s, --silent suppress warnings</div><div>　　--verbose 打印进度信息</div><div>　　-?, --help 给出该系统求助列表</div><div>　　--usage 给出简要的用法信息</div><div>　　-V, --version 打印程序版本号</div><div>　　Mandatory or optional arguments to long options are also mandatory or optional</div><div>　　for any corresponding short options.</div><div>　　用&#8220;glibcbug&#8221;脚本将错误报告给 &lt;bugs@gnu.org&gt;。</div><div>　　类似命令: piconv , convmv</div><div>　　piconv是流模式的,处理超大文件比较方便. convmv是给文件名重命名的,windows和linux系统间切换后尤其有用</div></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 17.27272605895996px; font-size: 12.727272033691406px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #fefef2;">首先，我们要知道支持的字符编码有哪些，这个可以用-l参数得到（List known coded character sets）。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 17.27272605895996px; font-size: 12.727272033691406px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #fefef2;">格式：iconv -l</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 17.27272605895996px; font-size: 12.727272033691406px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #fefef2;">其次，是怎样转换，如下所示：</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 17.27272605895996px; font-size: 12.727272033691406px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #fefef2;">格式：iconv -f from-encoding -t to-encoding inputfile</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 17.27272605895996px; font-size: 12.727272033691406px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #fefef2;">上面的调用方式，会把输出打印在屏幕上，如果要输出到文件，可以像下面这样</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 17.27272605895996px; font-size: 12.727272033691406px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #fefef2;">格式：iconv -f from-encoding -t to-encoding inputfile -o outputfile</p><img src ="http://www.cppblog.com/HappySky2046/aggbug/197426.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2013-01-20 16:54 <a href="http://www.cppblog.com/HappySky2046/archive/2013/01/20/197426.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Git 常用命令集合</title><link>http://www.cppblog.com/HappySky2046/archive/2012/11/29/195804.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Thu, 29 Nov 2012 10:44:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/11/29/195804.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/195804.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/11/29/195804.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/195804.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/195804.html</trackback:ping><description><![CDATA[<p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git config &#8212;global user.name &#8220;Nshen&#8221; //必须<br />git config &#8212;global user.email &#8220;nshen121@gmail.com&#8221; //必须<br />git config &#8212;global color.ui &#8220;always&#8221; //或者"auto", always不仅Base环境是彩色，Dos里也是彩色的。<br />git config &#8212;global core.editor notepad.exe //设为windows记事本<br />git config &#8212;global alias.ci &#8220;commit&#8221; //别名缩写<br />git config &#8212;global merge.tool //可以设置合并工具<br />git config &#8212;global &#8212;list //查看设置</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">其实最后这些设置都保存在C:\Documents and Settings\用户名\.gitconfig 文件下（windows）</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">查看帮助： git help command</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">初始化 :</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git init</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">纳入版本控制:</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git add *.txt //添加所有txt文件<br />git add README //添加单个文件<br />git add . //添加所有文件包括子目录，但不包括空目录</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">add命令是个多功能命令，根据目标文件的状态不同，此命令的效果也不同：可以用它开始跟踪新文件，或者把已跟踪的文件放到暂存区，还能用于合并时把有冲突的文件标记为已解决状态等）注意每次修改后都要重新add,不然就会提交之前add时的版本。</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git add -i //进入交互式add<br />git add -p //直接进入补丁模式，可以暂存修改的一部分。</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">提交：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git commit -m &#8220;initial project version&#8221;<br />git commit -m &#8220;something&#8221; someFile //提交指定文件<br />git commit -C HEAD -a &#8212;amend //复用HEAD留言，增补提交（修改小错误，而不增加提交记录，掩盖自己的小马虎）</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">参数:</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">-m &#8220;提交的说明&#8221;<br />-a 动把所有已经跟踪过的文件暂存,并提交.(工作目录中修改过的文件都提交到版本库，不需一个一个手动add了)<br />&#8212;amend 增补提交<br />-C 复用指定提交的提交留言<br />-c 打开编辑器在已有的提交基础上编辑修改</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">e.g 修改最后一次提交:</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git commit -m 'initial commit'git add forgotten_filegit commit --amend</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">如果没有修改就相当于更改提交说明,上边3个命令得到一个提交.</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">忽略提交的文件：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">所有人都需要忽略的文件要写在.gitignore文件里，而只有自己的个人偏好需要忽略的文件要写在.git/info/exclude文件中</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">语法：</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;"># 此为注释 &#8211; 将被 Git 忽略*.a # 忽略所有 .a 结尾的文件!lib.a # 但 lib.a 除外*.[oa] #忽略以.o或.a结尾的文件*~ #忽略以~结尾的文件/TODO # 仅仅忽略项目根目录下的 TODO 文件，不包括 subdir/TODObuild/ # 忽略 build/ 目录下的所有文件doc/*.txt # 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt查看文件改动：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git diff // 比较工作目录与缓存区的区别<br />git diff &#8212;cached 或者 git diff &#8212;staged //缓存区与版本库里的区别<br />git diff HEAD //三者的区别</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">请注意，单单 git diff 不过是显示还没有暂存起来的改动，而不是这次工作和上次提交之间的差异。所以有时候你一下子暂存了所有更新过的文件后，运行 git diff 后却什么也没有，就是这个原因。<br />git diff 18f822e //18f822e这个版本与当前目录的区别</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git diff aaaaa..bbbbb //比较aaaaa与bbbbb之间差别<br />git diff &#8212;stat可以统计数据，比较特别的命令</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">重命名，移动，删除文件：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git mv file_from file_to //改名或移动</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">$ git mv README.txt README$ git status# On branch master# Your branch is ahead of 'origin/master' by 1 commit.## Changes to be committed:#(use "git reset HEAD &lt;file&gt;..." to unstage)## renamed: README.txt -&gt; README</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">其实，运行 git mv 就相当于运行了下面三条命令：</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">$ mv README.txt README<br />$ git rm README.txt<br />$ git add README</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">必须调用 git rm 文件名 //从暂存区移除,并且文件也被删除</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">如果只是手工删除了文件,运行git status时会出现</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;"># Changed but not updated:#(use "git add/rm &lt;file&gt;..." to update what will be committed)## deleted: grit.gemspec</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">此时必须再运行 git rm 文件名,才会在提交时候不再纳入版本管理.<br />如果删除之前修改过并且已经add到缓存区了的话,则必须强制删除 -f</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">另外一种情况是，我们想把文件从Git仓库中删除（亦即从暂存区域移除），但仍然希望保留在当前工作目录中。换句话说，仅是从跟踪清单中删除。比如一些大型日志文件或者一堆.a编译文件，不小心纳入仓库后，要移除跟踪但不删除文件，以便稍后在 .gitignore 文件中补上，用 &#8212;cached 选项即可：</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">查看状态：查看当前状态:</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git status</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">$ git status# On branch master# Changes to be committed: //只要在这行后边的,说明放入暂存区了#(use "git reset HEAD &lt;file&gt;..." to unstage) //想取消放入缓存 git reset HEAD README## new file: README# Changed but not updated: //跟踪文件内容改变,但还没有放到暂存区,需要git add 命令才会放到暂存区#(use "git add &lt;file&gt;..." to update what will be committed)#(use "git checkout -- &lt;file&gt;..." to discard changes in working directory) //删除修改,恢复到之前版本,有危险 (如果想保留并且回退版本用stashing 和分支来处理)# modified: benchmarks.rb查看提交历史:</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git log</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">这时&#8220;j&#8221;向下浏览，&#8220;k&#8221;向上浏览，&#8220;q&#8221;退出</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git log &#8212;pretty=oneline //一行显示<br />&#8212;pretty=&#8220;%h %s&#8221; //以各种格式输出</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git log &#8211;p -2 //-p显示每次提交的内容差异 -2表示最近2次更改</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git log &#8212;since &#8220;5 hours&#8221;<br />&#8212;since &#8220;3 hours&#8221;<br />&#8212;since &#8220;1 minute&#8221;<br />&#8212;before =&#8220;2008-10.01&#8221;</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git log 27j34j3j..03u43u23 //最老版本..最新版本（不包括起点只包括终点）<br />git log 34j4j4..HEAD<br />git log fhfs8fh.. //省略HEAD<br />git log &#8220;HEAD^^&#8221;..&#8220;HEAD^&#8221; //windows必须加引号表示回溯上一个提交<br />git log -1 HEAD~1 //相当于git log -1 HEAD^</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">问责：查明谁修改了代码</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git blame hello.html //你也可以用"-L"参数在命令(blame)中指定开始和结束行:<br />git blame -L 12,+10 hello.html //12到22行<br />blame还可以跟踪内容复制，文件复制，略，见版本控制之道 79页</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">撤销：撤销缓存区的修改（没有commit的）</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git checkout head 文件名 //撤销暂存区的修改&nbsp;<br />git checkout head readme.txt todo.txt<br />git checkout head *.txt<br />git checkout head . //撤销所有</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">反转提交：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git revert HEAD //创建一个反向的新提交抵消原来的提交改动<br />如果需要反转多个，必须从最后的开始反转, 加 -n可以不马上提交，之后一起提交。<br />git revert -n HEAD<br />git revert -n 54efhds<br />git commit -m &#8220;revert head and 54efhds&#8221;</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">复位：还没有commit，让工作目录回到上次提交时的状态</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git reset &#8212;hard HEAD //所有未提交的内容清空，这会让"git diff" 和"git diff &#8212;cached"命令的显示法都变为空<br />git reset &#8212;soft HEAD //复位版本库，暂存差异，便于提交中发现错误需要更改时有用（例如私人密码放到里边了）</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">分支：在当前分支末梢建立分支：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git branch RB_1.0（建立分支不会自动切换过去）</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">切换分支：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git checkout RB_1.0（切换到RB_1.0分支）</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">创建并切换分支：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git checkout -b RB_1.0（简化上边2步操作）</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">删除分支：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git branch -d RB_1.0</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">基于某次提交、分支或标签创建新分支:</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git branch RB_1.0 master<br />git branch RB_1.0 6fe57de0<br />git branch Rb_1.01 1.0</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">查看分支：git branch //列出本地分支 iss53* master //*号表示当前所在分支 testing</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git branch -r //显示远程分支<br />git branch -a //列出所有分支</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">分支重命名：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git branch -m master mymaster<br />-M 大写M会覆盖同名的分支</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">合并分支：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">直接合并：<br />git merge 想合并到当前分支的源分支名<br />git merge &#8212;no-commit 分支 //合并但不提交</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">压合合并：将分支压合成一条commit记录，并合并过来<br />git merge &#8212;squash 某bug分支<br />git commit -m &#8220;修复某bug&#8221;</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">拣选合并：只合并一个提交<br />git cherry-pick 321d76f<br />如果需要连续拣选，就需要加 -n参数<br />然后再git commit ，但不要加-m参数，编辑器就会使用刚拣选的提交留言作为现在的留言。</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">标签Tag:查看标签:</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git tag</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">创建标签：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git tag 1.0 //在当前分支最后一次提交创建标签<br />git tag 1.0 RB_1.0 //基于RB_1.0分支的最新踢脚创建标签<br />git tag 1.0 ae468d8kt //为某次提交创建标签</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">检出标签：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git checkout 1.0 //检出标签与检出分支一样操作，但检出标签后用git branch查看本地分支会发现你现在不再任何分支上<br />这时你不应该修改，而应该立即基于此标签创建一个分支<br />git checkout -b from-1.0</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">变基：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">1）git rebase RB_1.01 //也许修改过一个bug，希望新版本变基到RB_1.01分支上<br />2）手动解决冲突 //如果解决不了直接git rebase&nbsp;-abort来跳过特定提交或完全放弃变基<br />3）git add xxx.html //冲突解决<br />4）git rebase &#8212;continue</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git rebase --onto HEAD^^ HEAD^ HEAD</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">//&#8212;onto参数可以改写历史抹掉中间的参数，将倒数第一个参数变基到倒数第3个参数，为防止出错建议在试验性分支上先试验。</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">rebase -i 可以排序历史记录，多个提交合并为1个，一个提交分解成多个提交 ，<br />详见版本控制之道p86 ，需要编辑器支持，windows记事本不行</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">远程相关：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git clone git://github.com/schacon/grit.git //从现有仓库克隆<br />git clone git://github.com/schacon/grit.git mygrit //换名,唯一区别就是新建的目录成了mygrit,其他都一样</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">添加远程仓库:</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git remote add pb git://github.com/paulboone/ticgit.git<br />clone会默认添加origin仓库，如果原本用git init创建的版本库，后来又想提交到远程版本库，就可以用下边的办法<br />git remote add origin git@example.com:/xxxxxx</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">查看远程分支：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git remote -v //查看远程仓库,默认clone后,应该有一个origin仓库,-v显示对应的clone地址<br />git remote show origin //查看远程仓库信息</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">远程仓库重命名和删除:</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git remote rename pb paul<br />git remote rm paul</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">获取数据：git fetch [remote-name] 拉取远程仓库到本地远程仓库,不自动合并 //$ git fetch origin$ git fetch pbremote: Counting objects: 58, done.remote: Compressing objects: 100% (41/41), done.remote: Total 44 (delta 24), reused 1 (delta 0)Unpacking objects: 100% (44/44), done.From git://github.com/paulboone/ticgit* [new branch] master -&gt; pb/master* [new branch] ticgit -&gt; pb/ticgit</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">现在pb/master可以在本地访问了,你可以合并到自己的某个分支,或者切换到这个分支看看有什么有趣的更新</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git pull 抓取数据合并到工作目录中当前分支</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">推送数据：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git push [remote-name] [branch-name] //默认为 git push origin master</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git push origin serverfix //推送分支，其实是下边一句的简化,提取我的 serverfix 并更新到远程仓库的 serverfix</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git push origin serverfix:serferfix</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git push origin :serverfix //这个语法用于删除,只要把分号前留空</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">其他：</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git gc //垃圾回收，每隔一段时间例如一个月运行一次可以减少磁盘占用空间。<br />git reflog //最后的保障,列出误删的东东<br />git bisect //二分查找，版本控制之道p124页，略</p><span style="color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">归档版本库，导出压缩包:</span><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; background-color: #ffffff;">git archive &#8212;format=格式 &#8212;prefix=目录/ 版本&gt;压缩包.zip<br />git archive &#8212;format=zip head&gt;test.zip<br />git archive &#8212;format=tar &#8212;prefix=mysite-1.0/ 1.0 | gzip&gt;mysite-1.0.tar.gz<br />git archive &#8212;format=zip &#8212;prefix=mysite-1.0/ 1.0 &gt;mysie-1.0.zip</p><img src ="http://www.cppblog.com/HappySky2046/aggbug/195804.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-11-29 18:44 <a href="http://www.cppblog.com/HappySky2046/archive/2012/11/29/195804.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>并行的几个层面</title><link>http://www.cppblog.com/HappySky2046/archive/2012/11/25/195643.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Sun, 25 Nov 2012 03:51:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/11/25/195643.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/195643.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/11/25/195643.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/195643.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/195643.html</trackback:ping><description><![CDATA[<span style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.200000762939453px; background-color: #ffffff;">并行是分多个层面的，个人认为基本上可以分为这么几个层面：1、指令级的并行；即所谓的微程序、指令流水线等，现在cpu的一级缓存、二级缓存都很大，所以这个cache的效果还是比较好的（基于局部性原理）2、线程级的并行；即同一个时刻多个函数在运行（现在的cpu好像都是多核的）3、服务级别的（比如一个游戏服务器中有商店服务、也有战斗服务、聊天服务等 这里的每个服务可能对应多个逻辑线程）4、节点级别的；即所谓的分布式系统，多个节点互相配合，使整个系统在逻辑上成为一个单一的系统。（google、qq等这些海量访问的服务统统是分布式的）一般来说，第一个级别的并行直接做在硬件里面，第二个级别的并行会有一些基础的框架，第三和第四个级别的并行就是应用程序自己的架构的问题了。<br /></span>并行库：TBB，FastFlow<h3><br /></h3><img src ="http://www.cppblog.com/HappySky2046/aggbug/195643.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-11-25 11:51 <a href="http://www.cppblog.com/HappySky2046/archive/2012/11/25/195643.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>redis event</title><link>http://www.cppblog.com/HappySky2046/archive/2012/08/03/186134.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Fri, 03 Aug 2012 03:18:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/08/03/186134.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/186134.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/08/03/186134.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/186134.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/186134.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: redis是单进程单线程事件多路循环处理所有的客户端连接，它的运行都是靠事件触发的。redis 的事件处理支持select、kqueue、epoll机制。其核心的poll函数aeApiPoll其实是一个封装函数，最终是调用 ae_select.c、ae_epoll.c还是ae_kqueue.c中的aeApiPoll（分别实现select、kqueue、epoll机制），取决于如下的宏定义：ae_s...&nbsp;&nbsp;<a href='http://www.cppblog.com/HappySky2046/archive/2012/08/03/186134.html'>阅读全文</a><img src ="http://www.cppblog.com/HappySky2046/aggbug/186134.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-08-03 11:18 <a href="http://www.cppblog.com/HappySky2046/archive/2012/08/03/186134.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>redis memory</title><link>http://www.cppblog.com/HappySky2046/archive/2012/08/02/186054.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Thu, 02 Aug 2012 09:36:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/08/02/186054.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/186054.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/08/02/186054.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/186054.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/186054.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这一节介绍redis中内存分配相关的api，下一节介绍redis内存使用过程中的一些细节。redis中所有的内存分配都由自己接管。主要由zmalloc.c和zmalloc.h中的zmalloc、zremalloc、zfree实现。Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighli...&nbsp;&nbsp;<a href='http://www.cppblog.com/HappySky2046/archive/2012/08/02/186054.html'>阅读全文</a><img src ="http://www.cppblog.com/HappySky2046/aggbug/186054.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-08-02 17:36 <a href="http://www.cppblog.com/HappySky2046/archive/2012/08/02/186054.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Redis string</title><link>http://www.cppblog.com/HappySky2046/archive/2012/08/02/186006.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Thu, 02 Aug 2012 02:58:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/08/02/186006.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/186006.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/08/02/186006.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/186006.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/186006.html</trackback:ping><description><![CDATA[<div><span style="color: #333333; font-family: Georgia, 'Bitstream Charter', serif; font-size: 16px; line-height: 24px; background-color: #ffffff; ">redis的字符串号称是二进制安全的，其内部实现其实就是个head+ char*。</span>&nbsp;<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->typedef&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*sds;<br />
<br />
<span style="color: #0000FF; ">struct</span>&nbsp;sdshdr&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;len; //&nbsp;<span style="color: #333333; font-family: Georgia, 'Bitstream Charter', serif; font-size: 16px; line-height: 24px; background-color: #ffffff; ">len 表示buf字符数组实际使用的空间大小，</span>&nbsp;<br />&nbsp; &nbsp; &nbsp;<span style="color: #0000FF; ">int</span>&nbsp;free; //<span style="color: #333333; font-family: Georgia, 'Bitstream Charter', serif; font-size: 16px; line-height: 24px; background-color: #ffffff; ">free表示buf剩余空间大小</span>&nbsp;<br />&nbsp; &nbsp; &nbsp;<span style="color: #0000FF; ">char</span>&nbsp;buf[]; //<span style="color: #333333; font-family: Georgia, 'Bitstream Charter', serif; font-size: 16px; line-height: 24px; background-color: #ffffff; ">buf所分配的空间大小等于len+free</span>&nbsp;<br />&nbsp;};<br />
<br />
<span style="color: #0000FF; ">static</span>&nbsp;inline&nbsp;size_t&nbsp;sdslen(<span style="color: #0000FF; ">const</span>&nbsp;sds&nbsp;s)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">struct</span>&nbsp;sdshdr&nbsp;*sh&nbsp;=&nbsp;(<span style="color: #0000FF; ">void</span>*)(s-(<span style="color: #0000FF; ">sizeof</span>(<span style="color: #0000FF; ">struct</span>&nbsp;sdshdr)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;sh-&gt;len;<br />
}<br />
<br />
<span style="color: #0000FF; ">static</span>&nbsp;inline&nbsp;size_t&nbsp;sdsavail(<span style="color: #0000FF; ">const</span>&nbsp;sds&nbsp;s)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">struct</span>&nbsp;sdshdr&nbsp;*sh&nbsp;=&nbsp;(<span style="color: #0000FF; ">void</span>*)(s-(<span style="color: #0000FF; ">sizeof</span>(<span style="color: #0000FF; ">struct</span>&nbsp;sdshdr)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;sh-&gt;free;<br />
}<br />
<br />
sds&nbsp;sdsnewlen(<span style="color: #0000FF; ">const</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;*init,&nbsp;size_t&nbsp;initlen);<br />
sds&nbsp;sdsnew(<span style="color: #0000FF; ">const</span>&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*init);<br />
sds&nbsp;sdsempty();<br />
size_t&nbsp;sdslen(<span style="color: #0000FF; ">const</span>&nbsp;sds&nbsp;s);<br />
sds&nbsp;sdsdup(<span style="color: #0000FF; ">const</span>&nbsp;sds&nbsp;s);<br />
<span style="color: #0000FF; ">void</span>&nbsp;sdsfree(sds&nbsp;s);<br />
size_t&nbsp;sdsavail(sds&nbsp;s);<br />
sds&nbsp;sdsgrowzero(sds&nbsp;s,&nbsp;size_t&nbsp;len);<br />
sds&nbsp;sdscatlen(sds&nbsp;s,&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;*t,&nbsp;size_t&nbsp;len);<br />
sds&nbsp;sdscat(sds&nbsp;s,&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*t);<br />
sds&nbsp;sdscatsds(sds&nbsp;s,&nbsp;sds&nbsp;t);<br />
sds&nbsp;sdscpylen(sds&nbsp;s,&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*t,&nbsp;size_t&nbsp;len);<br />
sds&nbsp;sdscpy(sds&nbsp;s,&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*t);<br />
<br />
sds&nbsp;sdscatvprintf(sds&nbsp;s,&nbsp;<span style="color: #0000FF; ">const</span>&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*fmt,&nbsp;va_list&nbsp;ap);<br />
sds&nbsp;sdscatprintf(sds&nbsp;s,&nbsp;<span style="color: #0000FF; ">const</span>&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*fmt,&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" />);<br />
<br />
sds&nbsp;sdstrim(sds&nbsp;s,&nbsp;<span style="color: #0000FF; ">const</span>&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*cset);<br />
sds&nbsp;sdsrange(sds&nbsp;s,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;start,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;end);<br />
<span style="color: #0000FF; ">void</span>&nbsp;sdsupdatelen(sds&nbsp;s);<br />
<span style="color: #0000FF; ">void</span>&nbsp;sdsclear(sds&nbsp;s);<br />
<span style="color: #0000FF; ">int</span>&nbsp;sdscmp(sds&nbsp;s1,&nbsp;sds&nbsp;s2);<br />
sds&nbsp;*sdssplitlen(<span style="color: #0000FF; ">char</span>&nbsp;*s,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;len,&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*sep,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;seplen,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;*count);<br />
<span style="color: #0000FF; ">void</span>&nbsp;sdsfreesplitres(sds&nbsp;*tokens,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;count);<br />
<span style="color: #0000FF; ">void</span>&nbsp;sdstolower(sds&nbsp;s);<br />
<span style="color: #0000FF; ">void</span>&nbsp;sdstoupper(sds&nbsp;s);<br />
sds&nbsp;sdsfromlonglong(<span style="color: #0000FF; ">long</span>&nbsp;<span style="color: #0000FF; ">long</span>&nbsp;value);<br />
sds&nbsp;sdscatrepr(sds&nbsp;s,&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*p,&nbsp;size_t&nbsp;len);<br />
sds&nbsp;*sdssplitargs(<span style="color: #0000FF; ">char</span>&nbsp;*line,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;*argc);</div>
</div><img src ="http://www.cppblog.com/HappySky2046/aggbug/186006.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-08-02 10:58 <a href="http://www.cppblog.com/HappySky2046/archive/2012/08/02/186006.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Redis list</title><link>http://www.cppblog.com/HappySky2046/archive/2012/08/02/186004.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Thu, 02 Aug 2012 02:51:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/08/02/186004.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/186004.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/08/02/186004.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/186004.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/186004.html</trackback:ping><description><![CDATA[<p style="background-color: #ffffff; border: 0px; margin: 0px 0px 24px; padding: 0px; vertical-align: baseline; color: #333333; font-family: Georgia, 'Bitstream Charter', serif; font-size: 16px; line-height: 24px; ">先简单介绍下redis中用到的链表，是在文件adlist.c和adlist.h中实现的。<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">typedef&nbsp;</span><span style="color: #0000FF; ">struct</span><span style="color: #000000; ">&nbsp;listNode&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">struct</span><span style="color: #000000; ">&nbsp;listNode&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">prev;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">struct</span><span style="color: #000000; ">&nbsp;listNode&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">next;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">value;<br />}&nbsp;listNode;<br /><br />typedef&nbsp;</span><span style="color: #0000FF; ">struct</span><span style="color: #000000; ">&nbsp;listIter&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;listNode&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">next;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;direction;<br />}&nbsp;listIter;<br /><br />typedef&nbsp;</span><span style="color: #0000FF; ">struct</span><span style="color: #000000; ">&nbsp;list&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;listNode&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">head;<br />&nbsp;&nbsp;&nbsp;&nbsp;listNode&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">tail;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">(</span><span style="color: #000000; ">*</span><span style="color: #000000; ">dup)(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">ptr);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">*</span><span style="color: #000000; ">free)(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">ptr);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">*</span><span style="color: #000000; ">match)(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">ptr,&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">key);<br />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;len;<br />}&nbsp;list;<br /><br /></span><span style="color: #008000; ">/*</span><span style="color: #008000; ">&nbsp;Functions&nbsp;implemented&nbsp;as&nbsp;macros&nbsp;</span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;listLength(l)&nbsp;((l)-&gt;len)</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;listFirst(l)&nbsp;((l)-&gt;head)</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;listLast(l)&nbsp;((l)-&gt;tail)</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;listPrevNode(n)&nbsp;((n)-&gt;prev)</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;listNextNode(n)&nbsp;((n)-&gt;next)</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;listNodeValue(n)&nbsp;((n)-&gt;value)</span><span style="color: #000000; "><br /><br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;listSetDupMethod(l,m)&nbsp;((l)-&gt;dup&nbsp;=&nbsp;(m))</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;listSetFreeMethod(l,m)&nbsp;((l)-&gt;free&nbsp;=&nbsp;(m))</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;listSetMatchMethod(l,m)&nbsp;((l)-&gt;match&nbsp;=&nbsp;(m))</span><span style="color: #000000; "><br /><br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;listGetDupMethod(l)&nbsp;((l)-&gt;dup)</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;listGetFree(l)&nbsp;((l)-&gt;free)</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;listGetMatchMethod(l)&nbsp;((l)-&gt;match)</span><span style="color: #000000; "><br /><br /></span><span style="color: #008000; ">/*</span><span style="color: #008000; ">&nbsp;Prototypes&nbsp;</span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br />list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">listCreate(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">);<br /></span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;listRelease(list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">list);<br />list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">listAddNodeHead(list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">list,&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">value);<br />list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">listAddNodeTail(list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">list,&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">value);<br />list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">listInsertNode(list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">list,&nbsp;listNode&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">old_node,&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">value,&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;after);<br /></span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;listDelNode(list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">list,&nbsp;listNode&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">node);<br />listIter&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">listGetIterator(list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">list,&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;direction);<br />listNode&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">listNext(listIter&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">iter);<br /></span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;listReleaseIterator(listIter&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">iter);<br />list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">listDup(list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">orig);<br />listNode&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">listSearchKey(list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">list,&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">key);<br />listNode&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">listIndex(list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">list,&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;index);<br /></span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;listRewind(list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">list,&nbsp;listIter&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">li);<br /></span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;listRewindTail(list&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">list,&nbsp;listIter&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">li);</span></div></p><p style="background-color: #ffffff; border: 0px; margin: 0px 0px 24px; padding: 0px; vertical-align: baseline; color: #333333; font-family: Georgia, 'Bitstream Charter', serif; font-size: 16px; line-height: 24px; ">实现中主要用到listNode、list、listIter三个结构，listNode代表链表中的每个节点，list指向整个链表，listIter是为了迭代访问整个list，内部其实就是个listNode指针。</p><p style="background-color: #ffffff; border: 0px; margin: 0px 0px 24px; padding: 0px; vertical-align: baseline; color: #333333; font-family: Georgia, 'Bitstream Charter', serif; font-size: 16px; line-height: 24px; ">listNode提供的prev、next指针将整个list链接成一个双向链表，保存的值是void *类型，对值的复制、释放、匹配操作是用在list中注册的三个函数指针dup、free、match完成的。</p><p style="background-color: #ffffff; border: 0px; margin: 0px 0px 24px; padding: 0px; vertical-align: baseline; color: #333333; font-family: Georgia, 'Bitstream Charter', serif; font-size: 16px; line-height: 24px; ">在list结构中，除提供对listNode中的值进行操作的三个函数指针外，还提供了head、tail指针，以指向list的头部和尾部。另外list的len保存了整个list的长度，方便对list是否为空的判断(纯属多余吧)。</p><p style="background-color: #ffffff; border: 0px; margin: 0px 0px 24px; padding: 0px; vertical-align: baseline; color: #333333; font-family: Georgia, 'Bitstream Charter', serif; font-size: 16px; line-height: 24px; ">listIter是为了遍历list，可以从头部、尾部开始遍历。用法可用如下伪代码表示：</p><pre prettyprint"="" style="background-color: #f7f7f7; border: 1px solid #cccccc; margin-top: 6px; margin-bottom: 24px; padding: 2px 7px; vertical-align: baseline; font-family: 'Courier 10 Pitch', Courier, monospace; color: #222222; font-size: 15px; overflow: auto; width: 627px; "><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; ">iter</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">=</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; ">listGetIterotr</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">(</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; ">list</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">,</span> <span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #008800; background-position: initial initial; background-repeat: initial initial; ">&lt;direction&gt;</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">);</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; "> </span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000088; background-position: initial initial; background-repeat: initial initial; ">while</span> <span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">((</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; ">node</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">=</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; ">listNext</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">(</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; ">iter</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">))</span> <span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">!=</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; ">NULL</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">)</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; "> </span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">{</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; "> 	</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #660066; background-position: initial initial; background-repeat: initial initial; ">DoSomethingWith</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">(</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; ">listNodeValue</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">(</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; ">node</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">));</span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #000000; background-position: initial initial; background-repeat: initial initial; "> </span><span style="background-color: transparent; border: 0px; margin: 0px; padding: 0px; vertical-align: baseline; color: #666600; background-position: initial initial; background-repeat: initial initial; ">}</span></pre><p style="background-color: #ffffff; border: 0px; margin: 0px 0px 24px; padding: 0px; vertical-align: baseline; color: #333333; font-family: Georgia, 'Bitstream Charter', serif; font-size: 16px; line-height: 24px; ">另外注意：在提供的增加、删除节点的api（listAddNodeHead、listAddNodeTail、listDelNode）中，并没有分配、释放节点 内部的value所用内存，需要调用者自己分配或者释放value所占的内存（除了分配和释放节点本身的内存外）。</p><p style="background-color: #ffffff; border: 0px; margin: 0px 0px 24px; padding: 0px; vertical-align: baseline; color: #333333; font-family: Georgia, 'Bitstream Charter', serif; font-size: 16px; line-height: 24px; ">乍一看没有提供修改某个节点的值的方法，但是由于listSearchKey、listIndex等方法返回了节点指针，故可以直接修改节点的value。</p><img src ="http://www.cppblog.com/HappySky2046/aggbug/186004.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-08-02 10:51 <a href="http://www.cppblog.com/HappySky2046/archive/2012/08/02/186004.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>redis 协议</title><link>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185921.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Wed, 01 Aug 2012 09:31:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185921.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/185921.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185921.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/185921.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/185921.html</trackback:ping><description><![CDATA[<p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">我们跟踪一个普通的get命令来遍历几个关键函数，熟悉协议处理的过程。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">你可以通过telnet或者redis_cli、利用lib库发送请求给redis server。前者的是一种裸协议的请求发送到服务端，而后两者会对键入的请求进行协议组装帮助更好的解析（常见的是长度放到前头，还有添加阿协议类型）。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">Requests格式</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">*参数的个数 CRLF $第一个参数的长度CRLF 第一个参数CRLF ... $第N个参数的长度CRLF 第N个参数CRLF</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">例如在redis_cli里键入get a，经过协议组装后的请求为</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">2\r\n$3\r\nget\r\n$1\r\na\r\n</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">下面这个图涵盖了接收request，处理请求，调用函数，发送reply的过程。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: center; "><a href="http://www.hoterran.info/wp-content/uploads/2011/07/redis_protocol_command.png" style="color: #2266aa; text-decoration: none; "><img size-large=""  wp-image-426"="" title="redis_protocol_command" src="http://www.hoterran.info/wp-content/uploads/2011/07/redis_protocol_command-1024x630.png" alt="" width="819" height="504" style="border: none; padding: 0px; max-width: 100%; display: block; margin-left: auto; margin-right: auto; " /></a></p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">redis的网络事件库，我们在<a href="http://www.hoterran.info/redis_eventlibrary" style="color: #2266aa; text-decoration: none; ">前面的文章</a>已经讲过，readQueryFromClient先从fd中读取数据，先存储在c-&gt;querybuf里(networking.c 823)。接下来函数processInputBuffer来解析querybuf，上面说过如果是telnet发送的裸协议数据是没有*打头的表示参数个数的辅助信息，针对telnet的数据跳到processInlineBuffer函数，而其他则通过函数processMultibulkBuffer。<br />这两个函数的作用一样，解析c-&gt;querybuf的字符串，分解成多参数到c-&gt;argc和c-&gt;argv里面，argc表示参数的个数，argv是个redis_object的指针数组，每个指针指向一个redis_object, object的ptr里存储具体的内容，对于&#8221;get a&#8220;的请求转化后，argc就是2，argv就是</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">(gdb) p (char*)(*c-&gt;argv[0])-&gt;ptr $28 = 0x80ea5ec "get" (gdb) p (char*)(*c-&gt;argv[1])-&gt;ptr $26 = 0x80e9fc4 "a"</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">协议解析后就执行命令。processCommand首先调用lookupCommand找到get对应的函数。在redis server 启动的时候会调用populateCommandTable函数（redis.c 830）把readonlyCommandTable数组转化成一个hash table（server.commands），lookupCommand就是一个简单的hash取值过程，通过key（get）找到相应的命令函数指针getCommand（ t_string.c 437）。<br />getCommand比较简单，通过另一个全局的server.db这个hash table来查找key，并返回redis object，然后通过addReplyBulk函数返回结果。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">下面介绍一下reply协议。<br />bulk replies是以$打头消息体，格式$值长度\r\n值\r\n，一般的get命令返回的结果就是这种个格式。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">redis&gt;get aaa $3\r\nbbb\r\n</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">对应的的处理函数addReplyBulk</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">addReplyBulkLen(c,obj); addReply(c,obj); addReply(c,shared.crlf);</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">error messag是以-ERR 打头的消息体，后面跟着出错的信息，以\r\n结尾，针对命令出错。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">redis&gt;d -ERR unknown command 'd'\r\n</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">处理的函数是addReplyError</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">addReplyString(c,"-ERR ",5); addReplyString(c,s,len); addReplyString(c,"\r\n",2);</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">integer reply 是以:打头，后面跟着数字和\r\n。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">redis&gt;incr a :2\r\n</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">处理函数是</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">addReply(c,shared.colon); addReply(c,o); addReply(c,shared.crlf);</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">status reply以+打头，后面直接跟状态内容和\r\n</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">redis&gt;ping +PONG\r\n</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">这里要注意reply经过协议加工后，都会先保存在c-&gt;buf里，c-&gt;bufpos表示buf的长度。待到事件分离器转到写出操作（sendReplyToClient）的时候，就把c-&gt;buf的内容写入到fd里，c-&gt;sentlen表示写出长度。当c-&gt;sentlen=c-&gt;bufpos才算写完。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">还有一种Multi-bulk replies，lrange、hgetall这类函数通常需要返回多个值，消息结构与请求的格式一模一样。相关的函数是setDeferredMultiBulkLength。临时数据存储在链表c-&gt;reply里，处理方式同其他的协议格式。</p><img src ="http://www.cppblog.com/HappySky2046/aggbug/185921.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-08-01 17:31 <a href="http://www.cppblog.com/HappySky2046/archive/2012/08/01/185921.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>redis 持久化</title><link>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185920.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Wed, 01 Aug 2012 09:30:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185920.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/185920.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185920.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/185920.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/185920.html</trackback:ping><description><![CDATA[<p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">redis有全量（save/bgsave）和增量（aof）的持久化命令。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">全量的原理就是遍历里所有的DB，在每个bucket，读取链表的key和value并写入dump.rdb文件（rdb.c 405）。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">save命令直接调度rdbSave函数，这会阻塞主线程的工作，通常我们使用bgsave。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">bgsave命令调度rdbSaveBackground函数启动了一个子进程然后调度了rdbSave函数，子进程的退出状态由 serverCron的backgroundSaveDoneHandler来判断，这个在<a href="http://www.hoterran.info/redis_replication" style="color: #2266aa; text-decoration: none; ">复制这篇文章</a>里讲到过，这里就不罗嗦了。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">除了直接的save、bgsave命令之外，还有几个地方还调用到rdbSaveBackground和rdbSave函数。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">shutdown：redis关闭时需要对数据持久化，保证重启后数据一致性，会调用rdbSave()。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">flushallCommand：清空redis数据后，如果不做立即执行一个rdbSave()，出现crash后，可能会载入含有老数据的dump.rdb。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">void flushallCommand(redisClient *c) {   touchWatchedKeysOnFlush(-1);   server.dirty += emptyDb();      // 清空数据   addReply(c,shared.ok);   if (server.bgsavechildpid != -1) {     kill(server.bgsavechildpid,SIGKILL);     rdbRemoveTempFile(server.bgsavechildpid);   }   rdbSave(server.dbfilename);    //没有数据的dump.db   server.dirty++; }</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">sync：当master接收到slave发来的该命令的时候，会执行rdbSaveBackground，这个以前也有提过。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">数据发生变化：在多少秒内出现了多少次变化则触发一次bgsave，这个可以在conf里配置</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">for (j = 0; j &lt; server.saveparamslen; j++) {   struct saveparam *sp = server.saveparams+j;    if (server.dirty &gt;= sp-&gt;changes &amp;&amp; now-server.lastsave &gt; sp-&gt;seconds) {      rdbSaveBackground(server.dbfilename);      break;   } }</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">增量备份就是aof，原理有点类似redo log。每次执行命令后如出现数据变化，会调用feedAppendOnlyFile，把数据写到server.aofbuf里。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">void call(redisClient *c, struct redisCommand *cmd) {   long long dirty;   dirty = server.dirty;   cmd-&gt;proc(c);        //执行命令   dirty = server.dirty-dirty;   if (server.appendonly &amp;&amp; dirty)     feedAppendOnlyFile(cmd,c-&gt;db-&gt;id,c-&gt;argv,c-&gt;argc);</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">待到下次循环的before_sleep函数会通过flushAppendOnlyFile函数把server.aofbuf里的数据write到append file里。<br />可以在redis.conf里配置每次write到append file后从page cache刷新到disk的规律。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; "># appendfsync always appendfsync everysec # appendfsync no</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">参数的原理MySQL的innodb_flush_log_at_trx_commit一样，是个比较影响io的一个参数，需要在高性能和不丢数据之间做tradeoff。软件的优化就是tradeoff的过程，没有银弹。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">一个疑问先写到server.aofbuf，然后再写到数据文件，过程中如果crash会不会丢数据呢？</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">答案是不会，为何？我们来看函数执行的步骤：</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">call() feedAppendOnlyFile() 下一次循环 beforeSleep()--&gt;flushAppendOnlyFile() aeMain()---&gt;sendReplyToClient()</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">只有执行完了flush之后才会通知客户端数据写成功了，所以如果在feed和flush之间crash，客户接会因为进程退出接受到一个fin包，也就是一个错误的返回，所以数据并没有丢，只是执行出了错。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">redis crash后，重启除了利用rdb重新载入数据外，还会读取append file(redis.c 1561)加载镜像之后的数据。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">激活aof，可以在redis.conf配置文件里设置</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">appendonly yes</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">也可以通过config命令在运行态启动aof</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">cofig set appendonly yes</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">aof最大的问题就是随着时间append file会变的很大，所以我们需要bgrewriteaof命令重新整理文件，只保留最新的kv数据。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">下面这个根据图形来描述一下aof的全过程，绿色的为aof.c里的函数，顺序从左到右。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; "><a href="http://www.hoterran.info/wp-content/uploads/2011/07/redis_aof1.png" style="color: #2266aa; text-decoration: none; "><img size-large=""  wp-image-386"="" title="redis_aof" src="http://www.hoterran.info/wp-content/uploads/2011/07/redis_aof1-1024x373.png" alt="" width="819" height="298" style="border: none; padding: 0px; max-width: 100%; margin: 2px 10px 5px 0px; display: inline; float: left; " /></a></p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">启动appendly，或者config set appendonly yes 都会触发函数rewriteAppendOnlyFileBackground，bgrewriteaof也调用该函数。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">实际最后调用的函数是rewriteAppendOnlyFile,这个函数与rdbSave和类似。保存全库的kv数据。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">在子进程做快照的过程中，kv的变化是先写到aofbuf里。如果存在bgrewritechildpid进程，变化数据还要写到server.bgrewritebuf里（aof.c 177）。<br />等子进程完成快照退出之时，由backgroundRewriteDoneHandler函数再把bgrwritebuf和全镜像两部分数据进行合并（aof.c 673）。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">合并后的aof文件才是最新的全库的镜像数据。</p><img src ="http://www.cppblog.com/HappySky2046/aggbug/185920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-08-01 17:30 <a href="http://www.cppblog.com/HappySky2046/archive/2012/08/01/185920.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>redis 复制</title><link>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185919.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Wed, 01 Aug 2012 09:29:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185919.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/185919.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185919.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/185919.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/185919.html</trackback:ping><description><![CDATA[<p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">redis的复制方法和机制都比较简单。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">slaveof masterip port</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">在slave端键入命令之后，就开启了从master到slave的复制。一个master可以有多个slave，master有变化的时候会主动的把命令传播给每个slave。slave同时可以作为其他的slave的master，前提条件是这个slave已经处于稳定状态（REDIS_REPL_CONNECTED）。slave在复制的开始阶段处于阻塞状态（sync_readline）无法对外提供服务。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">数据的有向图会让redis的运维很有搞头。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">slaveof no one</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">从slave状态的转换回master状态，切断与原master的数据同步。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">下面根据图形来描述一个复制全过程。<br /><a href="http://www.hoterran.info/wp-content/uploads/2011/06/redis_replication.png" style="color: #2266aa; text-decoration: none; "><img size-large=""  wp-image-340"="" title="redis_replication" src="http://www.hoterran.info/wp-content/uploads/2011/06/redis_replication-1024x432.png" alt="" width="717" height="302" style="border: none; padding: 0px; max-width: 100%; " /></a></p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">复制的顺序是从左到右。绿色的过程表示replstate复制状态的变迁，复制相关的函数主要在src/replication.c里，红色为master的复制函数，蓝色的为slave使用的复制函数。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">slave端接收到客户端的slaveof masterip ort命令之后，根据readonlyCommandTable找到对应的函数为slaveofCommand。slaveofCommand会保存masterip，masterport，并把server.replstate改成REDIS_REPL_CONNECT，然后返回给客户端OK。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">slave端主线程在已经注册时间事件serverConn（redis.c 518）里执行replicationCron（redis.c 646）来开始与master的连接。调用syncWithMaster()开始与master的通信。经过校验之后，会发送一个SYNC command给master端，然后打开一个临时文件用于存储接下来master发过来的rdb文件数据。再添加一个文件事件注册readSyncBulkPayload函数，这个就是接收rdb文件的数据的函数，然后修改状态为REDIS_REPL_TRANSFER。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">master接收到SYNC command后，跳转到syncCommand函数（replication.c 556）。syncCommand会调度rdbSaveBackground函数，启动一个子进程做一个全库的持久化rdb文件，并把状态改为REDIS_REPL_WAIT_BGSAVE_END。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">master的主线程的serverCron会等待做持久化的子进程的退出，并判断退出的状态是否是正常。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">if ((pid = wait3(&amp;statloc,WNOHANG,NULL)) != 0) { if (pid == server.bgsavechildpid) { backgroundSaveDoneHandler(statloc); } else { ....</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">如果子进程正常退出，会转到backgroundSaveDoneHandler函数。backgroundSaveDoneHandler 处理每次rdbSaveBackground成功后的收尾工作，并打开刚刚产生的rdb文件。然后注册一个sendBulkToSlave函数用于发送rdb文件，状态切换至REDIS_REPL_SEND_BULK。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">sendBulkToSlave作用就是根据上面打开的rdb文件，读取并发送到slave端，当文件全部发送完毕之后修改状态为REDIS_REPL_ONLINE。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">我们回到slave，上面讲到slave通过readSyncBulkPayload接收rdb数据，接收完整个rdb文件后，会清空整个数据库emptyDb()(replication.c 374)。然后就通过rdbLoad函数载入接收到的rdb文件，于是slave和master数据就一致了，再把状态修改为REDIS_REPL_CONNECTED。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">接下来就是master和slave之间增量的传递的增量数据，另外slave和master在应用层有心跳检测（replication.c 543），和超时退出（replication.c 511）。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">最后再给出一个replstate状态图</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; "><a href="http://www.hoterran.info/wp-content/uploads/2011/06/redis_replication_state1.png" style="color: #2266aa; text-decoration: none; "><img size-large=""  wp-image-343"="" title="redis_replication_state" src="http://www.hoterran.info/wp-content/uploads/2011/06/redis_replication_state1-1024x583.png" alt="" width="717" height="408" style="border: none; padding: 0px; max-width: 100%; " /></a></p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">slave端复制状态</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">REDIS_REPL_NONE：未复制的状态</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">REDIS_REPL_CONNECT：已经接收到slaveof命令，但未发出sync命令给master</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">REDIS_REPL_TRANSFER：已经发出sync，但还没接收完rdb文件</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">REDIS_REPL_CONNECTED：已经接收完rdb文件，开始增量接收复制内容</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">maste端redis_client的复制状态</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">REDIS_REPL_WAIT_BGSAVE_START：bgsave被抢占，等待bgsave为其持久化进行工作。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">REDIS_REPL_WAIT_BGSAVE_END：等待bgsave持久化rdb文件。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">REDIS_REPL_SEND_BULK：rdb文件已经生成。开始拷贝给slave。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">REDIS_REPL_ONLINE：rdb拷贝完毕，开始增量复制。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">另外在syncCommand函数里有几种可能性</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">bgsave进程未启动，则启动。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">bsave已启动，且已经存在另外的一个slave连接，已经由这个连接开启了bgsave，则等待bgsave完毕，共享这次的持久化。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">bsave已启动，但不是由slave连接所启动的，则等待下次bgsave的退出。在updateSlavesWaitingBgsave函数里再次启动bgsave进程。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">update:</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: center; "><a href="http://www.hoterran.info/wp-content/uploads/2011/07/redis_replication_interactive.png" style="color: #2266aa; text-decoration: none; background-color: #ffffcc; background-position: initial initial; background-repeat: initial initial; "><img size-large=""  wp-image-393"="" title="redis_replication_interactive" src="http://www.hoterran.info/wp-content/uploads/2011/07/redis_replication_interactive-1024x825.png" alt="" width="819" height="660" style="border: none; padding: 0px; max-width: 100%; display: block; margin-left: auto; margin-right: auto; " /></a></p><img src ="http://www.cppblog.com/HappySky2046/aggbug/185919.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-08-01 17:29 <a href="http://www.cppblog.com/HappySky2046/archive/2012/08/01/185919.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>redis 哈希表</title><link>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185918.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Wed, 01 Aug 2012 09:28:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185918.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/185918.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185918.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/185918.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/185918.html</trackback:ping><description><![CDATA[<p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">hashtable的实现有很多，redis的dict.c 是其中之一。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; "><a href="http://www.yupoo.com/photos/hoterran/81545854/" title="redis_dict" style="color: #2266aa; text-decoration: none; "><img src="http://pic.yupoo.com/hoterran/B9WaUQkX/medish.jpg" alt="redis_dict" width="640" height="409" border="0" style="border: none; padding: 0px; max-width: 100%; " /></a></p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">dict 包含了2个dictht hashtable ht[0], ht[1]。<br /><a href="https://github.com/antirez/hiredis/blob/master/dict.c#L89" style="color: #2266aa; text-decoration: none; ">client版本的dict</a>是没有dictht的概念。加入dictht的概念存在2个ht的目的是为了在rehash的时候可以平滑的迁移bucket里的数据，而不像client的dict要把老的hash table里的一次性的全部数据迁移到新的hash table，这在造成一个密集型的操作，在业务高峰期不可取。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">ht是hashtable的简称，实际上是一个指针数组，数组的个数由dictht-&gt;size决定，是DICT_HT_INITIAL_SIZE的整数倍。每个元素（bucket）指向一个dictEntry的单链表来解决hash的conflict。查询某个key，需要先hash，定位到bucket,再通过链表遍历。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">key经过hash函数后，与dictht-&gt;sizemask求与均分到ht的每个bucket上。dictht-&gt;used表示这个ht里包含的key的个数，也就是dictEntry的个数，每次dictAdd成功+1。链表的加入为头指针的方法加入，这样dictAdd更加的方便。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">随着key不断的添加，bucket下的单链表越来越长，查找、删除效率越来越低，需要对ht进行expand，增加bucket个数，让链表的长度减少。bucket数量的增多，原有bucket的key需要迁移到新的bucket上，于是有了rehash的这个过程。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">ht[1]就是为了rehash而产生，新的ht size是ht[0]的两倍2， 随着dictAdd，dictFind函数的调用，ht[0]的每个bucket会rehash加入到ht[1]里。dict-&gt;rehashidx 是ht[0] 需要rehash就是迁移到ht[1]的bucket的索引，从0开始直到ht-&gt;used==0。<br />rehash除了每次伴随dictAdd，dcitFind而迁移一个bucket的所有dictEntry，还有一种一次hash100个bucket，直到消耗了某个时间点为止的做法。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; "><strong style="color: #666666; ">rehash的步骤：</strong><br />拿到一个bucket， 遍历这个链表的每个kv，对key进行hash然后于sizemask求与，定位ht[1]的新bucket位置，<br />加入到链表，迁移后ht[0].used&#8211;，ht[1].used++。<br />直到ht[0].used=0，释放ht[0]的table，再赋值ht[0]= ht[1]，再把则ht[1]reset。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; "><strong style="color: #666666; ">rehash的期间：</strong><br />由于ht[1]是ht[0]size的2倍，每次dictAdd的时候都会rehash一次，不会出现后ht[1] 满了，而ht[0]还有数据的事情。<br />查询会先查ht[0]再查询ht[1]，在rehash的过程中，不会出现再次expand。<br />新的key加到ht[1]。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; "><strong style="color: #666666; ">expand的条件：</strong><br />table的位置已经满了，糟糕的hash函数造成的skrew导致永远不会expand。<br />key的个数除以table的大小，超过了dict_force_resize_ratio。</p><img src ="http://www.cppblog.com/HappySky2046/aggbug/185918.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-08-01 17:28 <a href="http://www.cppblog.com/HappySky2046/archive/2012/08/01/185918.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Redis 事件库</title><link>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185917.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Wed, 01 Aug 2012 09:27:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185917.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/185917.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/08/01/185917.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/185917.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/185917.html</trackback:ping><description><![CDATA[<p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">每个cs程序尤其是高并发的网络服务端程序都有自己的网络异步事件处理库，redis不例外。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">事件库仅仅包括ae.c、ae.h，还有3个不同的多路复用（本文仅描述epoll）的wrapper文件，事件库封装了框架调用的主循环函数，暴露了时间、文件事件注册和销毁函数，典型的依赖反转模式。<br />网络操作都在networking.c里，封装了常见的socket操作。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">我们从redis启动的main函数开始，从用户发出连接键入命令开始遍历网络事件库所涉及的函数，unix套接口相关函数不表。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">首先对几个最常用对象进行解释。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; "><a title="redis_ae" href="http://www.yupoo.com/photos/hoterran/81562781/" style="color: #2266aa; text-decoration: none; "><img src="http://pic.yupoo.com/hoterran/Ba83MNdZ/medish.jpg" border="0" alt="redis_ae" width="640" height="495" style="border: none; padding: 0px; max-width: 100%; " /></a></p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">//redis启动的时候（init_server()）会创建的一个全局使用的事件循环结构 typedef struct aeEventLoop { int maxfd;		//仅仅是select 使用 long long timeEventNextId; aeFileEvent events[AE_SETSIZE]; //用于保存epoll需要关注的文件事件的fd、触发条件、注册函数。 aeFiredEvent fired[AE_SETSIZE]; //epoll_wait之后获得可读或者可写的fd数组，通过aeFiredEvent-&gt;fd再定位到events。 aeTimeEvent *timeEventHead;	//以链表形式保存多个时间事件，每隔一段时间机会触发注册的函数。 int stop; void *apidata;			//每种多路复用方法的使用的私有变量，例如epoll就是epfd和一个事件数组;而select是保存rset、wset。 aeBeforeSleepProc *beforesleep;	// sleep之前调用的函数，有些事情是每次循环必须做的，并非文件、时间事件。 } aeEventLoop;  //文件可读写事件 typedef struct aeFileEvent { int mask; 			//触发条件：读、写 aeFileProc *rfileProc;		//当fd可读时执行的事件（accept，read） aeFileProc *wfileProc;		//当fd可写时执行的事件（write） void *clientData;               //caller 传入的数据指针 } aeFileEvent;  //超时时间事件 typedef struct aeTimeEvent { long long id; /* time event identifier. */ long when_sec; /* seconds */ long when_ms; /* milliseconds */ aeTimeProc *timeProc;		//当出现超时的时候所执行的事件 aeEventFinalizerProc *finalizerProc; void *clientData;                //caller传入的数据指针 struct aeTimeEvent *next;	//单链表指向下一个时间事件 } aeTimeEvent;  //从epoll_wait或者select返回的，已经触发的文件事件 typedef struct aeFiredEvent { int fd; int mask; } aeFiredEvent;</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">我们来模拟redis server 启动和用户键入命令的过程，先上图。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; "><a title="redis_network_event_arch" href="http://www.yupoo.com/photos/hoterran/81562782/" style="color: #2266aa; text-decoration: none; "><img src="http://pic.yupoo.com/hoterran/Ba83MQPv/T9pGW.png" border="0" alt="redis_network_event_arch" width="743" height="1630" style="border: none; padding: 0px; max-width: 100%; " /></a></p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">好吧，从main函数开始吧。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">// src/redis.c 853 server.el = aeCreateEventLoop();</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">创建一个aeEventLoop结构体，成员apidata指向一个aeApiState对象，如果使用epoll，fd是由epoll_create创建的全局epoll fd ，events[] 用于保存epoll_wait返回的事件组。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">// src/redis.c 866 server.ipfd = anetTcpServer(server.neterr,server.port,server.bindaddr);</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">创建监听。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">//   src/redis.c 903 aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL);</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">注册一个时间事件serverCron，作用以后再讲。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; "> //   src/redis.c 906 aeCreateFileEvent(server.el,server.ipfd,AE_READABLE,  acceptTcpHandler,NULL)</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">为监听fd的注册一个文件事件，首先把listenfd和触发条件epoll_ctl加入到全局的epoll fd进行监控。再以fd作为文件事件event数组index定位，mask填入只读，rfileProc填入acceptTcpHandler函数。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">// src/redis.c 1571 aeSetBeforeSleepProc(server.el,beforeSleep);</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">aeEventLoop注册一个beforeSleep函数，这个函数在主循环里每次会被调用，作用以后再讲。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">// src/ redis.c 1572 aeMain()</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">网络事件库的核心循环函数。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">// src/ae.c  379 aeCreateLoop-&gt;beforesleep()</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">就是上面注册的beforeSleep函数。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">// src/ae.c 275 aeProcessEvents(eventLoop, AE_ALL_EVENTS);</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">先调度aeApiPoll，用epoll_wait处理文件事件，返回的fd和触发条件先存储在eventLoop-&gt;fired[]里，然后根据fired[]每个事件的的fd，定位到events，根据触发条件调用已经注册的事件。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">文件事件处理完毕后，接下来就是处理超时时间事件，这里不表。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">假如有个用户连接上redis，则从redis servere就从上面的aeApiPoll的poll_wait返回，产生的只读事件会调度上面注册了acceptTcpHandler函数。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">// src/networking.c 390 acceptTcpHandler(eventLoop, fd, NULL, AE_READABLE)</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">accept返回产生了一个新连接的fd（这里省略了很多步骤），需要从新的连接读取数据，于是为这个fd注册可读事件。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">// src/networking.c 20 aeCreateFileEvent(server.el,fd,AE_READABLE,  readQueryFromClient, c)</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">于是调用了aeCreateFileEvent 为只读事件注册, 这里的步骤和上面的listen fd 一样。用epoll_ctl将fd加入到epoll fd里等待下次epoll_wait，再注册触发条件和readQueyFromClient函数，接着aeMain()继续执行等待用户的数据。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">假如用户在这个连接键入redis命令例如：set foo bar，redis server端将会从aeApiPoll的epoll_wait返回，和accept一样的处理方式。返回的fd填入到fired[]数组，通过fired[fd]-&gt;fd找到是哪个文件事件，找到events[fd]-&gt;rfielProc这个函数，就是上面注册的readQueyFromClient 函数。</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">//  src/networking.c 816 readQueyFromClient(server.el, fd, NULL, AE_READABLE)</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">这个函数首先会执行read从tcp buffer读取用户键入的命令（非阻塞io），然后处理buffer，找到对应的command（lookupCommand），接下来执行这个command（call(c,cmd)），命令执行完毕需要返回结果的时候，会再次注册一个文件事件</p><pre style="font-family: 'Courier New', Courier, mono; font-size: 12px; background-color: #efefef; margin-top: 5pt; padding-top: 5pt; padding-bottom: 5pt; padding-left: 5pt; white-space: pre-wrap; word-wrap: break-word; line-height: 19px; text-align: justify; ">// src/networking.c  71 aeCreateFileEvent(server.el, c-&gt;fd, AE_WRITABLE, sendReplyToClient, c)</pre><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">这样下次循环epoll_wait的时候就发现这个fd可写，于是就会执行sendReplyToClient，讲结果发送给client。</p><p style="font-family: Arial, sans-serif; line-height: 19px; text-align: justify; ">redis的这个网络事件库是比较标准的网络框架的模式，实现的功能不算多但够用。</p><img src ="http://www.cppblog.com/HappySky2046/aggbug/185917.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-08-01 17:27 <a href="http://www.cppblog.com/HappySky2046/archive/2012/08/01/185917.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>流媒体协议</title><link>http://www.cppblog.com/HappySky2046/archive/2012/07/22/184603.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Sun, 22 Jul 2012 05:42:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/07/22/184603.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/184603.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/07/22/184603.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/184603.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/184603.html</trackback:ping><description><![CDATA[<p style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif, 宋体; text-align: left; background-color: #000000; "><p align="left" style="font-size: 13px; line-height: 1.4; color: #000000; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color: #ffffff; "><span style="line-height: 1.5; font-size: 14pt; ">流媒体指的是在网络中使用流技术传输的连续时基媒体，其特点是在播放前不需要下载整个文件，而</span><span style="line-height: 1.5; font-size: 14pt; ">是采用边下载边播放的方式，它是视频会议、IP电话等应用场合的技术基础。RTP是进行实时流媒体传输</span><span style="line-height: 1.5; font-size: 14pt; ">的标准协议和关键技术，本文介绍如何在Linux下利用JRTPLIB进行实时流媒体编程。</span></p><p align="left" style="font-size: 13px; line-height: 1.4; color: #000000; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color: #ffffff; "><span style="line-height: 1.5; font-size: 14pt; ">一、流媒体简介</span><br /><span style="line-height: 1.5; font-size: 14pt; ">&nbsp;&nbsp;&nbsp;&nbsp; 随着Internet的日益普及，在网络上传输的数据已经不再局限于文字和图形，而是逐渐向声音和视频等多</span><span style="line-height: 1.5; font-size: 14pt; ">媒体格式过渡。目前在网络上传输音频/视频（Audio/Video，简称A/V）等多媒体文件时，基本上只有下</span><span style="line-height: 1.5; font-size: 14pt; ">载和流式传输两种选择。通常说来，A/V文件占据的存储空间都比较大，在带宽受限的网络环境中下载可</span><span style="line-height: 1.5; font-size: 14pt; ">能要耗费数分钟甚至数小时，所以这种处理方法的延迟很大。如果换用流式传输的话，声音、影像、动画</span><span style="line-height: 1.5; font-size: 14pt; ">等多媒体文件将由专门的流媒体服务器负责向用户连续、实时地发送，这样用户可以不必等到整个文件全</span><span style="line-height: 1.5; font-size: 14pt; ">部下载完毕，而只需要经过几秒钟的启动延时就可以了，当这些多媒体数据在客户机上播放时，文件的剩</span><span style="line-height: 1.5; font-size: 14pt; ">余部分将继续从流媒体服务器下载。</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 1.5; font-size: 14pt; ">流（Streaming）是近年在Internet上出现的新概念，其定义非常广泛，主要是指通过网络传输多媒体数</span><span style="line-height: 1.5; font-size: 14pt; ">据的技术总称。流媒体包含广义和狭义两种内涵：广义上的流媒体指的是使音频和视频形成稳定和连续的</span><span style="line-height: 1.5; font-size: 14pt; ">传输流和回放流的一系列技术、方法和协议的总称，即流媒体技术；狭义上的流媒体是相对于传统的下载</span><span style="line-height: 1.5; font-size: 14pt; ">-回放方式而言的，指的是一种从Internet上获取音频和视频等多媒体数据的新方法，它能够支持多媒体</span><span style="line-height: 1.5; font-size: 14pt; ">数据流的实时传输和实时播放。通过运用流媒体技术，服务器能够向客户机发送稳定和连续的多媒体数据</span><span style="line-height: 1.5; font-size: 14pt; ">流，客户机在接收数据的同时以一个稳定的速率回放，而不用等数据全部下载完之后再进行回放。</span><span style="line-height: 1.5; font-size: 14pt; ">由于受网络带宽、计算机处理能力和协议规范等方面的限制，要想从Internet上下载大量的音频和视频数</span><span style="line-height: 1.5; font-size: 14pt; ">据，无论从下载时间和存储空间上来讲都是不太现实的，而流媒体技术的出现则很好地解决了这一难题。</span><span style="line-height: 1.5; font-size: 14pt; ">目前实现流媒体传输主要有两种方法：顺序流（progressive streaming）传输和实时流（realtime&nbsp;</span><span style="line-height: 1.5; font-size: 14pt; ">streaming）传输，它们分别适合于不同的应用场合。</span></p><p align="left" style="font-size: 13px; line-height: 1.4; color: #000000; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color: #ffffff; "><span style="line-height: 1.5; font-size: 14pt; ">顺序流传输&nbsp;</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 1.5; font-size: 14pt; ">顺序流传输采用顺序下载的方式进行传输，在下载的同时用户可以在线回放多媒体数据，但给定时刻只能</span><span style="line-height: 1.5; font-size: 14pt; ">观看已经下载的部分，不能跳到尚未下载的部分，也不能在传输期间根据网络状况对下载速度进行调整。</span><span style="line-height: 1.5; font-size: 14pt; ">由于标准的HTTP服务器就可以发送这种形式的流媒体，而不需要其他特殊协议的支持，因此也常常被称作</span><span style="line-height: 1.5; font-size: 14pt; ">HTTP流式传输。顺序流式传输比较适合于高质量的多媒体片段，如片头、片尾或者广告等。</span><br /></p><p align="left" style="font-size: 13px; line-height: 1.4; color: #000000; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color: #ffffff; "><span style="line-height: 1.5; font-size: 14pt; ">实时流传输&nbsp;</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 1.5; font-size: 14pt; ">实时流式传输保证媒体信号带宽能够与当前网络状况相匹配，从而使得流媒体数据总是被实时地传送，因</span><span style="line-height: 1.5; font-size: 14pt; ">此特别适合于现场事件。实时流传输支持随机访问，即用户可以通过快进或者后退操作来观看前面或者后</span><span style="line-height: 1.5; font-size: 14pt; ">面的内容。从理论上讲，实时流媒体一经播放就不会停顿，但事实上仍有可能发生周期性的暂停现象，尤</span><span style="line-height: 1.5; font-size: 14pt; ">其是在网络状况恶化时更是如此。与顺序流传输不同的是，实时流传输需要用到特定的流媒体服务器，而</span><span style="line-height: 1.5; font-size: 14pt; ">且还需要特定网络协议的支持。</span></p>之所以以前对这几个有点分不清，是因为CTC标准里没有对RTCP进行要求，因此<strong style="word-break: break-all; ">在标准RTSP的代码中没有看到相关的部分。而在私有RTSP的代码中，有关控制、同步等，是在RTP Header中做扩展定义实现的</strong>。</p><p style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif, 宋体; text-align: left; background-color: #000000; ">另外，RFC3550可以看作是RFC1889的升级文档，只看RFC3550即可。</p><ul style="word-break: break-all; line-height: normal; margin: 0px 0px 0px 3em; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif, 宋体; text-align: left; background-color: #000000; "><li style="word-break: break-all; ">RTP：实时传输协议（Real-time Transport Protocol）<ul style="word-break: break-all; margin: 0px 0px 0px 3em; padding: 0px; "><li style="word-break: break-all; ">RTP/RTCP是实际传输数据的协议</li><li style="word-break: break-all; ">RTP传输音频/视频数据，如果是PLAY，Server发送到Client端，如果是RECORD，可以由Client发送到Server</li><li style="word-break: break-all; ">整个RTP协议由两个密切相关的部分组成：RTP数据协议和RTP控制协议（即RTCP）</li></ul></li><li style="word-break: break-all; ">RTSP：实时流协议（Real Time Streaming Protocol，RTSP）<ul style="word-break: break-all; margin: 0px 0px 0px 3em; padding: 0px; "><li style="word-break: break-all; ">RTSP的请求主要有DESCRIBE,SETUP,PLAY,PAUSE,TEARDOWN,OPTIONS等，顾名思义可以知道起对话和控制作用</li><li style="word-break: break-all; ">RTSP的对话过程中SETUP可以确定RTP/RTCP使用的端口，PLAY/PAUSE/TEARDOWN可以开始或者停止RTP的发送，等等</li></ul></li><li style="word-break: break-all; ">RTCP：<ul style="word-break: break-all; margin: 0px 0px 0px 3em; padding: 0px; "><li style="word-break: break-all; ">RTP/RTCP是实际传输数据的协议</li><li style="word-break: break-all; ">RTCP包括Sender Report和Receiver Report，用来进行音频/视频的同步以及其他用途，是一种控制协议</li></ul></li></ul><p style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif, 宋体; text-align: left; background-color: #000000; ">以下是每个协议的概要介绍：</p><p style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif, 宋体; text-align: left; background-color: #000000; "><strong style="word-break: break-all; ">一、RTP数据协议</strong>&nbsp;<br style="word-break: break-all; " />&nbsp;&nbsp;&nbsp; RTP数据协议负责对流媒体数据进行封包并实现媒体流的实时传输，每一个RTP数据报都由头部（Header）和负载（Payload）两个部分组成，其中头部前12个字节的含义是固定的，而负载则可以是音频或者视频数据。RTP数据报的头部格式如图1所示：</p><p align="center" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; "><br style="word-break: break-all; " /><img alt="" src="http://www-128.ibm.com/developerworks/cn/linux/l-mdst/image001.jpg" title="点击图片可在新窗口打开" style="word-break: break-all; max-width: 635px; cursor: pointer; " /></p><p align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;其中比较重要的几个域及其意义如下：&nbsp;</p><ul style="word-break: break-all; margin: 0px 0px 0px 3em; padding: 0px; "><li style="word-break: break-all; "><div align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">CSRC记数（CC）：表示CSRC标识的数目。CSRC标识紧跟在RTP固定头部之后，用来表示RTP数据报的来源，RTP协议允许在同一个会话中存在多个数据源，它们可以通过RTP混合器合并为一个数据源。例如，可以产生一个CSRC列表来表示一个电话会议，该会议通过一个RTP混合器将所有讲话者的语音数据组合为一个RTP数据源。&nbsp;</div></li><li style="word-break: break-all; "><div align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">负载类型（PT）：标明RTP负载的格式，包括所采用的编码算法、采样频率、承载通道等。例如，类型2表明该RTP数据包中承载的是用ITU G.721算法编码的语音数据，采样频率为8000Hz，并且采用单声道。&nbsp;</div></li><li style="word-break: break-all; "><div align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">序列号：用来为接收方提供探测数据丢失的方法，但如何处理丢失的数据则是应用程序自己的事情，RTP协议本身并不负责数据的重传。&nbsp;</div></li><li style="word-break: break-all; "><div align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">时间戳：记录了负载中第一个字节的采样时间，接收方能够时间戳能够确定数据的到达是否受到了延迟抖动的影响，但具体如何来补偿延迟抖动则是应用程序自己的事情。</div></li></ul><p align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif, 宋体; background-color: #000000; ">&nbsp;&nbsp;&nbsp; 从RTP数据报的格式不难看出，它包含了传输媒体的类型、格式、序列号、时间戳以及是否有附加数据等信息，这些都为实时的流媒体传输提供了相应的基础。RTP协议的目的是提供实时数据（如交互式的音频和视频）的端到端传输服务，因此<strong style="word-break: break-all; ">在RTP中没有连接的概念</strong>，它可以建立在底层的面向连接或面向非连接的传输协议之上；RTP也不依赖于特别的网络地址格式，而仅仅只需要底层传输协议支持组帧（Framing）和分段（Segmentation）就足够了；另外<strong style="word-break: break-all; ">RTP本身还不提供任何可靠性机制</strong>，这些都要由传输协议或者应用程序自己来保证。在典型的应用场合下，RTP一般是在传输协议之上作为应用程序的一部分加以实现的，如图2所示：</p><div align="center" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; "><img alt="" src="http://www-128.ibm.com/developerworks/cn/linux/l-mdst/image002.jpg" title="点击图片可在新窗口打开" style="word-break: break-all; max-width: 635px; cursor: pointer; " /></div><p align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; "></p><p align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; "><span style="word-break: break-all; line-height: normal !important; font-size: 14pt; "><strong style="word-break: break-all; ">二、RTCP控制协议&nbsp;<br style="word-break: break-all; " /></strong>&nbsp;&nbsp;&nbsp;&nbsp;RTCP控制协议需要与RTP数据协议一起配合使用，当应用程序启动一个RTP会话时将同时占用两个端口，分别供RTP和RTCP使用。<strong style="word-break: break-all; ">RTP本身并不能为按序传输数据包提供可靠的保证，也不提供流量控制和拥塞控制，这些都由RTCP来负责完成</strong>。通常RTCP会采用与RTP相同的分发机制，向会话中的所有成员周期性地发送控制信息，应用程序通过接收这些数据，从中获取会话参与者的相关资料，以及网络状况、分组丢失概率等反馈信息，从而能够对服务质量进行控制或者对网络状况进行诊断。</span></p><p align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; "><span style="word-break: break-all; line-height: normal !important; font-size: 14pt; ">&nbsp;&nbsp;&nbsp; RTCP协议的功能是通过不同的RTCP数据报来实现的，主要有如下几种类型：</span></p><span style="word-break: break-all; font-size: 14pt; "><ul style="word-break: break-all; margin: 0px 0px 0px 3em; padding: 0px; "><li style="word-break: break-all; "><div align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">SR：发送端报告，所谓发送端是指发出RTP数据报的应用程序或者终端，发送端同时也可以是接收端。</div></li><li style="word-break: break-all; "><div align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">RR：接收端报告，所谓接收端是指仅接收但不发送RTP数据报的应用程序或者终端。</div></li><li style="word-break: break-all; "><div align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">SDES：源描述，主要功能是作为会话成员有关标识信息的载体，如用户名、邮件地址、电话号码等，此外还具有向会话成员传达会话控制信息的功能。</div></li><li style="word-break: break-all; "><div align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">BYE：通知离开，主要功能是指示某一个或者几个源不再有效，即通知会话中的其他成员自己将退出会话。</div></li><li style="word-break: break-all; "><div align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">APP：由应用程序自己定义，解决了RTCP的扩展性问题，并且为协议的实现者提供了很大的灵活性。</div></li></ul><p align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">&nbsp;&nbsp;&nbsp; RTCP数据报携带有服务质量监控的必要信息，能够对服务质量进行动态的调整，并能够对网络拥塞进行有效的控制。由于RTCP数据报采用的是多播方式，因此会话中的所有成员都可以通过RTCP数据报返回的控制信息，来了解其他参与者的当前情况。<br style="word-break: break-all; " />&nbsp;&nbsp;&nbsp;&nbsp;在一个典型的应用场合下，发送媒体流的应用程序将周期性地产生发送端报告SR，该RTCP数据报含有不同媒体流间的同步信息，以及已经发送的数据报和字节的计数，接收端根据这些信息可以估计出实际的数据传输速率。另一方面，接收端会向所有已知的发送端发送接收端报告RR，该RTCP数据报含有已接收数据报的最大序列号、丢失的数据报数目、延时抖动和时间戳等重要信息，发送端应用根据这些信息可以估计出往返时延，并且可以根据数据报丢失概率和时延抖动情况动态调整发送速率，以改善网络拥塞状况，或者根据网络状况平滑地调整应用程序的服务质量。</p><p align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; "></p><p align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; "><strong style="word-break: break-all; line-height: normal !important; ">三、RTSP实时流协议</strong>&nbsp;<br style="word-break: break-all; line-height: normal !important; " />&nbsp;&nbsp;&nbsp; 作为一个应用层协议，RTSP提供了一个可供扩展的框架，它的意义在于使得实时流媒体数据的受控和点播变得可能。总的说来，RTSP是一个流媒体表示协议，主要用来控制具有实时特性的数据发送，但它本身并不传输数据，而是必须依赖于下层传输协议所提供的某些服务。<strong style="word-break: break-all; ">RTSP可以对流媒体提供诸如播放、暂停、快进等操作，它负责定义具体的控制消息、操作方法、状态码等，此外还描述了与RTP间的交互操作（RFC2326）</strong>。</p><p align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;<strong style="word-break: break-all; ">RTSP在制定时较多地参考了HTTP/1.1协议，甚至许多描述与HTTP/1.1完全相同</strong>。RTSP之所以特意使用与HTTP/1.1类似的语法和操作，在很大程度上是为了兼容现有的Web基础结构，正因如此，HTTP/1.1的扩展机制大都可以直接引入到RTSP中。<br style="word-break: break-all; line-height: normal !important; " />&nbsp;&nbsp;&nbsp; 由RTSP控制的媒体流集合可以用表示描述（Presentation Description）来定义，所谓表示是指流媒体服务器提供给客户机的一个或者多个媒体流的集合，而表示描述则包含了一个表示中各个媒体流的相关信息，如数据编码/解码算法、网络地址、媒体流的内容等。<br style="word-break: break-all; line-height: normal !important; " />&nbsp;&nbsp;&nbsp;&nbsp;虽然RTSP服务器同样也使用标识符来区别每一流连接会话（Session），但RTSP连接并没有被绑定到传输层连接（如TCP等），也就是说在整个RTSP连接期间，RTSP用户可打开或者关闭多个对RTSP服务器的可靠传输连接以发出RTSP 请求。此外，RTSP连接也可以基于面向无连接的传输协议（如UDP等）。</p><p align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">&nbsp;&nbsp;&nbsp; RTSP协议目前支持以下操作：</p><ul style="word-break: break-all; margin: 0px 0px 0px 3em; padding: 0px; "><li style="word-break: break-all; "><div align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">检索媒体：允许用户通过HTTP或者其它方法向媒体服务器提交一个表示描述。如表示是组播的，则表示描述就包含用于该媒体流的组播地址和端口号；如果表示是单播的，为了安全在表示描述中应该只提供目的地址。</div></li><li style="word-break: break-all; "><div align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">邀请加入：媒体服务器可以被邀请参加正在进行的会议，或者在表示中回放媒体，或者在表示中录制全部媒体或其子集，非常适合于分布式教学。</div></li><li style="word-break: break-all; "><div align="left" style="word-break: break-all; line-height: 1.8em !important; margin: 15px 0px; ">添加媒体：通知用户新加入的可利用媒体流，这对现场讲座来讲显得尤其有用。与HTTP/1.1类似，RTSP请求也可以交由代理、通道或者缓存来进行处理。</div></li></ul></span><img src ="http://www.cppblog.com/HappySky2046/aggbug/184603.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-07-22 13:42 <a href="http://www.cppblog.com/HappySky2046/archive/2012/07/22/184603.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏UI库</title><link>http://www.cppblog.com/HappySky2046/archive/2012/06/03/177336.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Sun, 03 Jun 2012 08:36:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/06/03/177336.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/177336.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/06/03/177336.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/177336.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/177336.html</trackback:ping><description><![CDATA[<div><span style="font-family: Arial; line-height: 20px; font-size: 12px; color: #595959; letter-spacing: 1px; ">CEGUI是老牌的开源<span href="tag.php?name=%BD%E7%C3%E6" style="line-height: normal; ">界面</span>库了，最新版本是0.7.1，完全免费，也是Ogre官方推荐使用的界面库，Ogre1.6及以前的版本，都是内置支持的。使用它的商业游戏也非常多，比如天龙八部，火炬之光，仙剑四等。这也就证明CEGUI确实强大，可以完全达到商业应用级别，而且相关资料非常丰富，至少不用担心某个功能无法实现，因为你能碰到的问题，网上基本都有解决方案，经过这些大作的证明，就不要怀疑了：）。<br style="line-height: normal; " />但是功能强大是有代价的，就是它太庞大、复杂了，上手很困难。这些大作没有一个不修改CEGUI的，也就是说要真正用起来，或者说要用的好，还是要做点事的。那需要做多少事呢？不清楚。<br style="line-height: normal; " /><br style="line-height: normal; " /><br style="line-height: normal; " />此帖售价 10&nbsp;<span href="tag.php?name=%D2%FD%C7%E6" style="line-height: normal; ">引擎</span>币,已有 4 人购买 购买人名单zhangjiq1983squallcodefishtonchenghuai11<br style="line-height: normal; " />2. Ogre SDKTray<br style="line-height: normal; " />从Ogre1.7开始就不再内置支持CEGUI了，转而使用Ogre自己的SDKTray，&#8220;tray&#8221;是在ogre的overlay和material的基础上实现的，使用很容易理解和使用，但目前它还只是个半成品，无法应用到商业游戏中。<br style="line-height: normal; " /><br style="line-height: normal; " />3.QuickGUI<br style="line-height: normal; " /><br style="line-height: normal; " />最新版本10.1，专为Ogre写的UI库，支持Ogre1.7，比起CEGUI来说，小巧了很多。<br style="line-height: normal; " />但是很遗憾，至今还有没有编辑器（作者的Blog上说正在开发，但是还没有发布），要靠手动编写xml文件，囧啊～～Ogre社区里从来没有人推荐使用这个。我只是简单看了下，感觉像是作者练手的项目（个人观点）。<br style="line-height: normal; " /><br style="line-height: normal; " />4.Hikari<br style="line-height: normal; " /><br style="line-height: normal; " />Hikari可以让你使用Flash制作界面，最新版本0.3，完全免费，大家知道Flash动画是非常流行的，如果将Flash应用到游戏中，一定很拉风！Hikari就实现了这个功能，通过Flash.ocx将swf渲染成Ogre的Texture，然后你就可以任意操作这个Texture了，正是因为如此，Hikari支持Flash的所有版本，不存在兼容性问题。因为Flash本身就支持多国语言，所以中文显示也没有问题。可以把界面开发的大部分内容放到Flash那边，从而使客户端简洁很多（简单就是美啊）。<br style="line-height: normal; " />但是Hikari最致命的问题的<span href="tag.php?name=%D0%A7%C2%CA" style="line-height: normal; ">效率</span>太低，它使用的是Flash的ocx，先将动画内容渲染到DC上，然后拷到Texture中，所以很慢，而且慢的是第二步，使得Flash优秀的脏矩形优势无法发挥，根本无法应用到商业游戏中。我做了个动画，30张图片随机飘动，1023x768的窗口，使Flash占满，Release版只能跑到15帧（集成显卡），这还没有显示任何文字呢：（<br style="line-height: normal; " /><br style="line-height: normal; " />5.Scaleform<br style="line-height: normal; " /><br style="line-height: normal; " />Scaleform跟Hikari的作用是一样的，都是用Flash来做游戏界面，不同的是Scaleform非常牛X，它的效率很高，可以说是最强游戏界面解决方案了！而且对亚洲语言显示和输入都完美支持。目前最新版本是3.2，据说4.0将支持Actionscript 3.0, 并全方位支持3D UI。超过600款游戏使用Scaleform做界面，比如超大作StarCraft II，Crysis，Fable II，Civilization IV，Halo Wars，Princes of Persia，Mess Effect 2，Prototype，Resistance 2，Splinter Cell等。<br style="line-height: normal; " />心动了吧，可惜Scaleform是收费的，而且授权费相当的高，3.X版的目标售价是每一款游戏2.5万美金。如果你不在乎钱的话，这绝对是不二之选，在乎钱的话，这是二B之选。PS：有不少商业引擎已经将Scaleform集成进去了，比如Gamebryo，Unreal3等，如果你不用Ogre，买了商业引擎也爽了～～<br style="line-height: normal; " /><br style="line-height: normal; " />6.ogreSwf/vektrix<br style="line-height: normal; " />Hikari效率太低，Scaleform太贵，ogreSwf/vektrix就是出来解决这个矛盾的。ogreSwf跟Scaleform一样都由开源的gameSwf发展起来，Scaleform开始商业化，ogreswf继续开源，后来ogreswf项目停掉了。2010年ogreSwf的作者重起了该项目，在原来的基础上改进并改名为vektrix，2010年4月发布了新的demo，可能是SourceForge的原因，我下的demo文件无法解压，又觉得vektrix目前还无法达到Scaleform的高度，所以后来就没有再试了。<br style="line-height: normal; " /><br style="line-height: normal; " />7.Awesomium<br style="line-height: normal; " /><br style="line-height: normal; " />Awesomium的功能有点类似Hikari，只不过它是将网页渲染成Texture，而且效率方面也做的比较好。Awesomium 采用了目前业界速度最快的浏览器内核webkit和v8，其实是把Chrome内核嵌入到了里面，同时还很好地支持flash，可以通过javascript使游戏和网页交互。该项目最初也是开源的，后来商业化了，但是不太贵，最便宜的版本只要400多美金。<br style="line-height: normal; " />Awesomium的效率之所以高，估计也是脏矩形方面做的好，我把上面那个动画嵌到网页中，用Awesomium打开，帧数马上就下来了，所以还是不能做UI，但是游戏中的帮助页面则可以考虑用这个。Awesomium也不方便根据网页内的内容做半透明效果，也就是网页中部分半透明很难实现，全透明，也就是镂空效果则可以通过<span href="tag.php?name=%C4%A3%B0%E5" style="line-height: normal; ">模板</span>实现。<br style="line-height: normal; " /><br style="line-height: normal; " />8.MYGUI<br style="line-height: normal; " /><br style="line-height: normal; " />MyGUI最新版本3.0.1，是俄罗斯人写的，要么没有<span href="tag.php?name=%D7%A2%CA%CD" style="line-height: normal; ">注释</span>，要么注释是俄文的，而且相关的资料实在是太缺乏了，虽然小修改一下可以支持中文显示，但是效果太差了，根本不能用，更别说多种文字，多种效果了，目前也没有什么商业游戏是用这个库做的。<br style="line-height: normal; " />但我最终选择了这个UI库。<br style="line-height: normal; " />就像MYGUI的介绍一样&#8220;MyGUI - fast, simple and flexible GUI.&#8221;这确实是一个，高效，轻便，灵活的库。首先它的设计很好，所以即使没有注释，也不难理解。换肤的设计避免了CEGUI里的很多中间层，使用要简单很多，资源文件的管理也要清爽（清楚+爽）一些。没有使用ogre的overlay，用底层直接画了，效率比CEGUI要高。LayoutEdit，ImageSetEdit等比CEGUI的要好用的多，CEGUI的工具经常当掉- -。中文显示可以模仿CEGUI去做，我已经完全实现，效率并不低，完全可以接受。<br style="line-height: normal; " />载入layout文件后返回一个窗口的vector，你可以自己写一个类似BaseLayout的类去管理，然后像MYGUI一样大量用C++委托做回调函数，就可以把各个Dialog分开去写，就像写MFC的Dialog一样，这一点做的实在太好了。如果再学一点CEGUI，把Lua脚本集成进去，载入layout文件时把窗口注册到lua中，这样就可以在脚本里写逻辑了，客户端-UI-脚本，很清晰。<br style="line-height: normal; " />为什么没有商业游戏使用MYGUI呢？MYGUI比较稳定的版本2.2.3是09年10月份发布的，是少要1年才能有游戏出来，火炬之光是09年11月上市的，在开发的时候MYGUI还很不完善，以后一定会有不少游戏使用MYGUI：）<br style="line-height: normal; " />跟使用CEGUI一样，MYGUI也要做大量修改才能用到游戏中。<br style="line-height: normal; " />9.Libroket<br style="line-height: normal; " /><br style="line-height: normal; " /><br style="line-height: normal; " />LibRocket开发者为Wandering Monster Studios。LibRocket是一个基于HTML和CSS标准的C++用户界面中间件包。它设计为项目的界面设计提供解决方案。 跨平台支持：Windows、Mac OSX(intel) and Linux。<br style="line-height: normal; " /><br style="line-height: normal; " />10.&nbsp;&nbsp; Menus Master<br style="line-height: normal; " /><br style="line-height: normal; " />开发者为法国巴黎的Omegame公司。Omegame公司开发和授权Menus Master，该产品提供一整套用户界面创作工具。帮助设计师和工程师用最短的时间，利用各种资源(2D 位图、矢量图、3D对象，视频，声音)，开发出复杂UI，包括2D和3D前端、游戏内UI、Heads Up Display(HUD)。<br style="line-height: normal; " /><br style="line-height: normal; " />Menus Master由三个模块组成：<br style="line-height: normal; " />1.Menus Master Studio：由美工使用，提供一个用户友好的可视化界面来创建任何类型的游戏UI。<br style="line-height: normal; " />2.Menus Master Data Generator：是一个处理模块，将game UI<span href="tag.php?name=%D7%AA%BB%BB" style="line-height: normal; ">转换</span>成Menus Master Development kit可以使用的数据。<br style="line-height: normal; " />3. Menus Master Development kit：是SDK,让程序员将game UI与游戏整合起来。<br style="line-height: normal; " /><br style="line-height: normal; " />11.GLO<br style="line-height: normal; " /><br style="line-height: normal; " />GLO是一个独立于平台专门用于游戏开发的免费的图形用户界面库。该引擎可以作为一个C / C + +库，整合到大多数游戏引擎中。</span></div><img src ="http://www.cppblog.com/HappySky2046/aggbug/177336.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-06-03 16:36 <a href="http://www.cppblog.com/HappySky2046/archive/2012/06/03/177336.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TW的经验</title><link>http://www.cppblog.com/HappySky2046/archive/2012/06/03/177325.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Sun, 03 Jun 2012 04:52:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/06/03/177325.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/177325.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/06/03/177325.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/177325.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/177325.html</trackback:ping><description><![CDATA[<div><span style="font-family: Verdana; line-height: normal; font-size: 12px; ">在ThoughtWorks日常的面试中，大致会分为多个回合，每个回合由不同的人采用不同的方式来面试，例如电话，笔试，面对面交流等等。一般能够通过这样的流程的人，大多可以接受，一般的公司也都采用这样流程招聘开发人员。电话面试的主要意图是要考察求职者的个人经历。因此，求职者应多谈自己：自己在团队中做了什么，自己挽回了什么错误，自己的责任是什么，自己带来了什么影响，自己存在什么问题。面试者看中的是这个人的表达能力，他所发挥的作用，他个人经历，他的信心。问问题也多为开放问题，并经常要追着问他某个项目中的某件事情，并要求他举例来说。<br />笔试一般为写代码或其他题目，对于代码，我一般要先看这个人的简历，根据他的工作年限和经历，判断他的代码应该是什么水平。对于未毕业的学生，不妨有所宽松，对于工作很久的人，如果他好学上进，接受新鲜的事物和新鲜思路多的话，代码应该是什么样子。这样的标准大概在90%的情况下是准确的。<br />Joe Homs 写了一篇 如何被我面试 很清楚的写出了各种过程的注意事项。对于技术人员的面试，相信每个做过开发人员招聘的人都会有所体会。技术问题很好度量，说一是一，很容易。然而，对于一些技术要求低一点的职位，如何面试就成了很微妙的问题。例如BA，PM等。<br />很多BA和PM很久没有写代码了，考察他们代码无疑是浪费时间。对于BA和PM，你可以不需要技术有多好，但你应该对技术有sense。至少别人正在用的新技术你知道是怎么回事。很多时候，BA和PM会在项目前期出现在客户处，决定一个项目的初始技术选择。<br /><br />电话面试一个非技术人员也很麻烦，他们天天看别的PM和BA做事，你怎么知道他说的是他看到的还是他自己实践过的？所以很多时候，要追着一个问题问到底。这时候逻辑分析很重要，有的人前后说话会有矛盾，这就说明了他的说法有虚假之处，要小心。<br />我公司在面试的时候，有套逻辑题比较特别。对于Developer，当然要要求很好的逻辑才行。对BA和PM逻辑要求也不能低。例如BA，很多时候会面对逻辑比较差的客户，不能被侃晕是不是。<br />一个很tricky的事情是，许多人，可能觉得BA是要求比较低的工作，在申请公司职位的时候，觉得达不到Developer的要求才申请BA。我可以明确的告诉这样的人，BA不比Developer要求低，甚至在某些方面比对Developer要求更高，例如专注细节，例如交流，表达，组织，管理等等。一个差的BA，比一个差的Developer更能搞砸项目。<br />对于BA的面试，我经常采用角色扮演的方式来进行。我扮演客户，另一个同事扮演开发人员，我们一起面试一个BA candidate。我描述一些简单的需求，要求这个BA来分析和整理，并最终转述给开发人员。从这个过程中，很容易就能看出这个人是不是真正的做过需求管理的工作，是不是能够顺畅的表达，是不是能用一些巧妙地方法来获取真正的需求。<br />另一个难以面试的是PM。国内的PM很多时候扮演的更像是&#8220;政委&#8221;的角色。他负责管人和管理客户关系，主要靠做思想工作来控制团队，搞平衡。很少见有PM 真正的做项目进度、成本、范围、质量控制，或者说，在这些方面做的比较欠缺。而这样的PM，面试时候也很头大。敏捷团队中，人和思想基本上不需要太多控制，更多的是需要项目经理真正的监控项目本身的属性，理解项目并领导项目。<br />对于一些想要转行的人，例如作了很久Developer想要做BA了，这样公司也支持。面试的时候就主要看潜质了，也就是学习和接受能力。但如果一个人是因为做某方面实在做不下去了才要转行，那还是好好做回原来那份有前途的工作好。公司鼓励每个人多方面发展。一个Developer也应该具备BA或PM技能，BA也应可以兼任PM，QA也可以转行当BA，这种每个人都了解其他知识，每个都负责的团队，才是最好的团队。</span></div><img src ="http://www.cppblog.com/HappySky2046/aggbug/177325.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-06-03 12:52 <a href="http://www.cppblog.com/HappySky2046/archive/2012/06/03/177325.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基层管理</title><link>http://www.cppblog.com/HappySky2046/archive/2012/06/01/177122.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Fri, 01 Jun 2012 15:27:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/06/01/177122.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/177122.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/06/01/177122.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/177122.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/177122.html</trackback:ping><description><![CDATA[<div><span style="color: #333333; font-family: Arial, serif; font-size: 13px; ">&nbsp;引用 &nbsp;<a href="http://www.crazycoder.cn/ProjectManagement/Article175760.html">http://www.crazycoder.cn/ProjectManagement/Article175760.html</a><br />&nbsp; &nbsp; 几乎每种行业都有基层主管（或基层管理人员），而软件行业的基层主管一般是项目经理、技术经理、开发经理、组长等。其职责是资源协调、风险预估、项目管控、团队建设，说白一点大多数的企业现状就是项目负责人带领团队攻下一个又一个项目的过程。很多公司以项目成败作为项目负责人考核的唯一标准，因为项目规模、成本、客户满意度等容易量化，并且是直接跟公司的利润有很大关系；而相反团队建设却难以衡量，如何衡量一个普通技工晋升成高级技工到底是基层主管的培养还是原员工本身就具备高级技工的技能。因此，难免出现以项目额度论英雄的局面，这样往往造成一将功成万骨枯的悲壮场面，并不利于团队的发展。卡耐基曾经说过，带走我的员工，把我的工厂留下，不久后工厂就会长满杂草；拿走我的工厂，把我的员工留下，不久后我们还会有个更好的工厂。我的观点是，从短期目标来看，项目成功是解决温饱问题的指标，如果温饱问题未解决，还如何谈吃得好，如团队经常疯狂加班赶项目就是温饱尚未解决的一种表现；从长远角度来看，团队建设是迈向&#8220;吃得好&#8221;的改进过程，或着说是一种手段。<br />一只狮子带领一群绵羊的团队会战胜由一只绵羊带领一群狮子的团队。如果你是一只绵羊，配备一群狮子般的团队也是枉然。说到这里，我曾经从一个电视节目看到十多只年轻狮子攻击一头河马，由于缺乏领队，结果导致河马成功逃过一劫并且一头狮子牺牲这样难以置信的场面。后来，同样这群狮子在一只经验丰富的狮子带领下，战胜比河马更强壮更凶猛的对手。<br />&nbsp;&nbsp; &nbsp; &nbsp;基层主管往往来自基层的优秀员工，在成功转型之前必须先把自己的宝剑磨利。在NBA赛场上，5个科比组成的球队可能会输给联盟任何一只球队一个项目一般需要若干个成员组成团队&#8212;&#8212;售前、需求、设计、开发、测试、部署等。而现实情况往往是，要么项目急、要么人员未到位，或者两种情况都有，那么开发人员由于在公司所占比例大，可能会兼做需求和测试。这样造成的后果是，需求把握不明确，测试不到位导致软件质量差，客户不断投诉。正如下象棋一样，必须了解各种棋子的角色和作用，以及它们应该摆放的位置。否则拿车当兵使，后果可想而知。<br />&nbsp;&nbsp; &nbsp; 当项目出现危机，基层主管的第一反应是？如果第一反应是&#8220;这个问题是哪个兔崽子造成的&#8221;，意味着该主管的思维是先追究责任。有一次，需要向客户演示现有的开发成果，由于各种原因导致离演示的前一天发现很多功能都未完善，如果照这样演示给客户看的话简直是演猴戏。当时，基层主管唯有向上汇报，而高级主管的第一反应是，评估完善这些功能需要多少时间？现在增加资源是否能够缩短工期？需要哪些资源才能完成？并且在该项目所有成员目前表示，他不想追究任何一个人的错误，首要任务是先分析如何能够解决问题。事后，他再向基层主管了解如何改进才能避免同类问题的发生，通过这种方式相当于给基层主管上了一次深刻的管理课程。<br />&nbsp;&nbsp; &nbsp; 聆听团队的意见。善于聆听是良好沟通的铺垫。如果你的团队成员在他的岗位上老老实实的干了几个月，突然他有一天告诉你（或者从其他成员了解到），他觉得自己的工作没意思。这其实不完全是分工的问题，很大程度上是沟通出现问题。试问，他是觉得没意思，而不是不合适，即他胜任这份工作，可惜觉得缺少了什么，可能是缺少锻炼机会、想换个项目等等。主动去了解团队成员的意向，因为把他们放在感兴趣的岗位会发挥他们潜在的能力。当然并不是每个人都能找到适合自己的岗位，恰当的给予激励会鼓舞士气，保持工作的热情。某些基层主管把开空头支票当激励，结果失信于团队。<br />&nbsp;&nbsp; &nbsp;最大限度地发挥团队的力量是每个基层主管的职责。最大限度地发挥团队的力量的前提是得深入了解每个团队成员的技能和喜好。特别是软件工程师，很多不善于语言表达也不会表现自己，更多的需要基层主管去观察。如A君喜欢钻研技术但是缺乏经验，如果有技术难度较高地先分配给他，帮他分析解决方案，更重要的是给他信心。<br />&nbsp;&nbsp;&nbsp;不要说我以为。基层主管不同于普通员工，一旦犯错就勇于承担。如果说&#8220;我以为&#8230;，想不到会&#8230;，结果造成&#8230;&#8221;，是一种借口，是不成熟的表现。<br />&nbsp;&nbsp;&nbsp;让团队主动反馈。基层主管要了解他管理的不是一群机器，是一支优秀的队伍。如果把团队训练成机器，最终会累死基层主管。例如，你需要挨个挨个的去问他们工作进展的怎么样，或者索性让他们写日报周报来反馈。这样得到的结果就是一切看起来很美好，而实际情况就可能隐藏一个个定时炸弹。如果并非团队成员的主动反馈，&#8220;被反馈&#8221;往往是走走形式，例如某某说&#8220;A功能完成了，B功能差不多了&#8221;。到了第二天、第三天还是&#8220;B功能差不多了&#8221;。主动反馈是简要说说工作的问题和解决方法，如某某说&#8220;A功能解决方案是&#8230;，B功能遇到&#8230;问题，C功能预计明天可完成&#8221;，并且更重要的是，不是等到你去问他才反馈。<br />&nbsp;&nbsp; 以上纯粹是自己对基层管理的个人看法，也是自己一些微薄经验的一个小结，思维有点混乱。这里抛砖引玉，希望听到更多的建议。</span></div><img src ="http://www.cppblog.com/HappySky2046/aggbug/177122.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-06-01 23:27 <a href="http://www.cppblog.com/HappySky2046/archive/2012/06/01/177122.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ 单元测试</title><link>http://www.cppblog.com/HappySky2046/archive/2012/06/01/177032.html</link><dc:creator>探路者</dc:creator><author>探路者</author><pubDate>Fri, 01 Jun 2012 02:37:00 GMT</pubDate><guid>http://www.cppblog.com/HappySky2046/archive/2012/06/01/177032.html</guid><wfw:comment>http://www.cppblog.com/HappySky2046/comments/177032.html</wfw:comment><comments>http://www.cppblog.com/HappySky2046/archive/2012/06/01/177032.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/HappySky2046/comments/commentRss/177032.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/HappySky2046/services/trackbacks/177032.html</trackback:ping><description><![CDATA[<div><span style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; line-height: 25px; "><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "></p><div><a rel="nofollow" style="line-height: 25px; text-decoration: none; color: #506f62; "><span style="line-height: 25px; "><strong><div><span style="color: #000000; font-weight: normal; "><strong style="line-height: 25px; ">单元测试概述</strong></span></div></strong></span></a></div>测试并不只是测试工程师的责任，对于开发工程师，为了保证发布给测试环节的代码具有足够好的质量（ Quality ），为所编写的功能代码编写适量的单元测试是十分必要的。<p>&nbsp;</p><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><strong style="line-height: 25px; ">单元测试</strong>（ Unit Test ，模块测试）是开发者编写的一小段代码，用于检验被测代码的一个很小的、很明确的功能是否正确，通过编写单元测试可以在编码阶段发现程序编码错误，甚至是程序设计错误。</p><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">单元测试不但可以增加开发者对于所完成代码的自信，同时，好的单元测试用例往往可以在回归测试的过程中，很好地保证之前所发生的修改没有破坏已有的程序逻辑。因此，单元测试不但不会成为开发者的负担，反而可以在保证开发质量的情况下，加速迭代开发的过程。</p><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">对 于单元测试框架，目前最为大家所熟知的是 JUnit 及其针对各语言的衍生产品， C++ 语言所对应的 JUnit 系单元测试框架就是 CppUnit 。但是由于 CppUnit 的设计严格继承自 JUnit ，而没有充分考虑 C++ 与 Java 固有的差异（主要是由于 C++ 没有反射机制，而这是 JUnit 设计的基础），在 C++ 中使用 CppUnit 进行单元测试显得十分繁琐，这一定程度上制约了 CppUnit 的普及。笔者在这里要跟大家介绍的是一套由 google 发布的开源单元测试框架（ Testing Framework ）： googletest 。<br /><br /><div><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><a rel="nofollow" style="line-height: 25px; text-decoration: none; color: #506f62; "><span style="line-height: 25px; ">应用 googletest 编写单元测试代码</span></a></p><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">googletest 是由 Google 公司发布，且遵循 New BSD License （可用作商业用途）的开源项目，并且 googletest 可以支持绝大多数大家所熟知的平台。与 CppUnit 不同的是： googletest 可以自动记录下所有定义好的测试，不需要用户通过列举来指明哪些测试需要运行。</p><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><a rel="nofollow" style="line-height: 25px; text-decoration: none; color: #506f62; "><span style="line-height: 25px; ">定义单元测试</span></a></p><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">在应用 googletest 编写单元测试时，使用 TEST() 宏来声明测试函数。如：<br /><div><a rel="nofollow" style="line-height: 25px; text-decoration: none; color: #506f62; "><strong style="line-height: 25px; ">清单 1. 用 TEST() 宏声明测试函数</strong></a><br style="line-height: 25px; " /><table border="0" cellpadding="0" cellspacing="0" width="100%" style="line-height: 25px; "><tbody style="line-height: 25px; "><tr style="line-height: 25px; "><td style="line-height: 25px; "><pre style="line-height: 25px; ">TEST(GlobalConfigurationTest, configurationDataTest) <br style="line-height: 25px; " /> TEST(GlobalConfigurationTest, noConfigureFileTest)</pre></td></tr></tbody></table><br style="line-height: 25px; " /><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">分别针对同一程序单元 GlobalConfiguration 声明了两个不同的测试（Test）函数，以分别对配置数据进行检查（ configurationDataTest ），以及测试没有配置文件的特殊情况（ noConfigureFileTest ）。</p></div><div><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><a rel="nofollow" style="line-height: 25px; text-decoration: none; color: #506f62; "><span style="line-height: 25px; ">实现单元测试</span></a></p><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">针对同一程序单元设计出不同的测试场景后（即划分出不同的 Test 后），开发者就可以编写单元测试分别实现这些测试场景了。</p><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">在 googletest 中实现单元测试，可通过 ASSERT_* 和 EXPECT_* 断言来对程序运行结果进行检查。 ASSERT_* 版本的断言失败时会产生致命失败，并结束当前函数； EXPECT_* 版本的断言失败时产生非致命失败，但不会中止当前函数。因此， ASSERT_* 常常被用于后续测试逻辑强制依赖的处理结果的断言，如创建对象后检查指针是否为空，若为空，则后续对象方法调用会失败；而 EXPECT_* 则用于即使失败也不会影响后续测试逻辑的处理结果的断言，如某个方法返回结果的多个属性的检查。</p><p style="line-height: 25px; margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">googletest 中定义了如下的断言：<br /><div><table border="0" cellpadding="0" cellspacing="0" style="line-height: 25px; "><tbody style="line-height: 25px; "><tr style="line-height: 25px; "><td style="line-height: 25px; vertical-align: top; "><strong style="line-height: 25px; ">基本断言</strong></td><td style="line-height: 25px; vertical-align: top; "><strong style="line-height: 25px; ">二进制比较</strong></td><td style="line-height: 25px; vertical-align: top; "><strong style="line-height: 25px; ">字符串比较</strong></td></tr><tr style="line-height: 25px; "><td style="line-height: 25px; vertical-align: top; ">ASSERT_TRUE(<em style="line-height: 25px; ">condition</em>);<br style="line-height: 25px; " />EXPECT_TRUE(<em style="line-height: 25px; ">condition</em>);<br style="line-height: 25px; " /><em style="line-height: 25px; ">condition</em>为真<br style="line-height: 25px; " />ASSERT_FALSE(<em style="line-height: 25px; ">condition</em>);<br style="line-height: 25px; " />EXPECT_FALSE(<em style="line-height: 25px; ">condition</em>);<br style="line-height: 25px; " /><em style="line-height: 25px; ">condition</em>为假</td><td style="line-height: 25px; vertical-align: top; ">ASSERT_EQ(<em style="line-height: 25px; ">expected</em>,<em style="line-height: 25px; ">actual</em>);<br style="line-height: 25px; " />EXPECT_EQ(<em style="line-height: 25px; ">expected</em>,<em style="line-height: 25px; ">actual</em>);<br style="line-height: 25px; " /><em style="line-height: 25px; ">expected</em>==<em style="line-height: 25px; ">actual</em><br style="line-height: 25px; " />ASSERT_NE(<em style="line-height: 25px; ">val1</em>,<em style="line-height: 25px; ">val2</em>);<br style="line-height: 25px; " />EXPECT_NE(<em style="line-height: 25px; ">val1</em>,<em style="line-height: 25px; ">val2</em>);<br style="line-height: 25px; " /><em style="line-height: 25px; ">val1</em>!=<em style="line-height: 25px; ">val2</em><br style="line-height: 25px; " />ASSERT_LT(<em style="line-height: 25px; ">val1</em>,<em style="line-height: 25px; ">val2</em>);<br style="line-height: 25px; " />EXPECT_LT(<em style="line-height: 25px; ">val1</em>,<em style="line-height: 25px; ">val2</em>);<br style="line-height: 25px; " /><em style="line-height: 25px; ">val1</em>&lt;<em style="line-height: 25px; ">val2</em><br style="line-height: 25px; " />ASSERT_LE(<em style="line-height: 25px; ">val1</em>,<em style="line-height: 25px; ">val2</em>);<br style="line-height: 25px; " />EXPECT_LE(<em style="line-height: 25px; ">val1</em>,<em style="line-height: 25px; ">val2</em>);<br style="line-height: 25px; " /><em style="line-height: 25px; ">val1</em>&lt;=<em style="line-height: 25px; ">val2</em><br style="line-height: 25px; " />ASSERT_GT(<em style="line-height: 25px; ">val1</em>,<em style="line-height: 25px; ">val2</em>);<br style="line-height: 25px; " />EXPECT_GT(<em style="line-height: 25px; ">val1</em>,<em style="line-height: 25px; ">val2</em>);<br style="line-height: 25px; " /><em style="line-height: 25px; ">val1</em>&gt;<em style="line-height: 25px; ">val2</em><br style="line-height: 25px; " />ASSERT_GE(<em style="line-height: 25px; ">val1</em>,<em style="line-height: 25px; ">val2</em>);<br style="line-height: 25px; " />EXPECT_GE(<em style="line-height: 25px; ">val1</em>,<em style="line-height: 25px; ">val2</em>);<br style="line-height: 25px; " /><em style="line-height: 25px; ">val1</em>&gt;=<em style="line-height: 25px; ">val2</em></td><td style="line-height: 25px; vertical-align: top; ">ASSERT_STREQ(<em style="line-height: 25px; ">expected_str</em>,<em style="line-height: 25px; ">actual_str</em>);<br style="line-height: 25px; " />EXPECT_STREQ(<em style="line-height: 25px; ">expected_str</em>,<em style="line-height: 25px; ">actual_str</em>);<br style="line-height: 25px; " />两个 C 字符串有相同的内容<br style="line-height: 25px; " />ASSERT_STRNE(<em style="line-height: 25px; ">str1</em>,<em style="line-height: 25px; ">str2</em>);<br style="line-height: 25px; " />EXPECT_STRNE(<em style="line-height: 25px; ">str1</em>,<em style="line-height: 25px; ">str2</em>);<br style="line-height: 25px; " />两个 C 字符串有不同的内容<br style="line-height: 25px; " />ASSERT_STRCASEEQ(<em style="line-height: 25px; ">expected_str</em>,<em style="line-height: 25px; ">actual_str</em>);<br style="line-height: 25px; " />EXPECT_STRCASEEQ(<em style="line-height: 25px; ">expected_str</em>,<em style="line-height: 25px; ">actual_str</em>);<br style="line-height: 25px; " />两个 C 字符串有相同的内容，忽略大小写<br style="line-height: 25px; " />ASSERT_STRCASENE(<em style="line-height: 25px; ">str1</em>,<em style="line-height: 25px; ">str2</em>);<br style="line-height: 25px; " />EXPECT_STRCASENE(<em style="line-height: 25px; ">str1</em>,<em style="line-height: 25px; ">str2</em>);<br style="line-height: 25px; " />两个 C 字符串有不同的内容，忽</td></tr></tbody></table></div></p></div></p></div></p></span></div><img src ="http://www.cppblog.com/HappySky2046/aggbug/177032.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/HappySky2046/" target="_blank">探路者</a> 2012-06-01 10:37 <a href="http://www.cppblog.com/HappySky2046/archive/2012/06/01/177032.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>