Monday, November 23, 2009

版本管理工具TortoiseSVN介绍[转]

subversion(简称svn)是近年来崛起的版本管理工具,是cvs的接班人。

怎么使用svn呢?在Windows下,最常用的svn客户端是TortoiseSVN,有时简称为TSVN。

什么是 TortoiseSVN?
  TortoiseSVN 是 Subversion 版本控制系统的一个免费开源客户端,可以超越时间的管理文件和目录。文件保存在中央版本库,除了能记住文件和目录的每次修改以外,版本库非常像普通的文件服务器。你可以将文件恢复到过去的版本,并且可以通过检查历史知道数据做了哪些修改,谁做的修改。这就是为什么许多人将 Subversion 和版本控制系统看作一种"时间机器"。

TortoiseSVN安装

下载后,安装。重启机器,使目录图标生效。

在资源管理器中,鼠标右键点击任意位置,右键菜单中出现"SVN Checkout",即为安装成功。

svn操作流程

开发人员使用svn进行开发的一般流程是:
checkout(检出)项目
——> 更新文件或目录 ——>update
——> 修改文件或目录 ——> commit(提交)变更
——> 增加文件或目录 ——> add(增加) 文件或目录——> commit(提交)
——> 删除文件或目录 ——>commit(提交)上一级目录

其中,checkout只进行一次,update、commit、add操作根据需要会经常使用。

checkout(检出)操作

在资源管理器中,鼠标右键点击任意位置,在菜单中选择"SVN Checkout"。

出现对话框,在"URL of repository:"中输入svn串,格式是"协议://ip:port/版本库/项目/目录"。根据实际情况输入,例如http://code.google.com/p/google-web-toolkit/source。如有疑问,向svn服务器管理员询问。

在"checkout directory"中输入本地存放代码的目录,请选择空目录或新目录。svn会清空该目录下的一切文件。输入完毕,点击"ok"按钮。

如果需要,会提示输入用户名和密码。选上"Save authentication"后,以后可以自动登录,不必重输密码。

checkout…有时候时间会很长。结束,点"ok"。

update(更新)操作

在资源管理器中,选择本地目录或文件,鼠标右键菜单选择"SVN Update"。会提示有无文件需要更新,点"ok"完成。

commit(提交)操作

把本地目录中变化了的文件或目录提交到版本库中,用commit操作。增加新文件或目录,要先用add,再commit。删除文件或目录,commit上一级目录。

在资源管理器中,选择本地目录或文件,鼠标右键菜单选择"SVN Commit"。

显示分上下2个框的界面。在上框输入说明文字,建议写版本号或变更原因,以便将来查找。下框列出提交的内容。没有可提交的内容,下框中会显示一段说明文字。点"ok"。

提交结束,显示结果。点"ok"。

解决代码冲突

如果commit时出现"You have to update your work copy first."红色警告,说明版本库中的此文件已经被其他人修改了。请先点"ok"按钮退出。执行update,然后再commit。

如果修改与update得到的代码不冲突,则自动合并。如果冲突(比如对同一行代码进行了修改),则出现"One or more files are in a conflicted state."红色警告,并产生几个文件记录冲突。一般情况下,我们不要直接编辑冲突文件。而按照以下操作手工解决冲突。

在资源管理器中,选择commit时冲突的那个文件,鼠标右键菜单选择"Edit conficts"。

出现界面,分为"Theirs"、"Mine"和"Merged"3部分,表示"别人修改的内容"、 "我修改的内容"和"合并后的结果"3部分。我们是要将"别人修改的内容"和"我修改的内容"有取舍地合并起来,形成"合并后的结果"。

合并一般分为4种情况:

  • 保留"我的修改",舍弃"别人的修改"。鼠标右键点击Mine框的相应行,点击"Use this text block"。
  • 舍弃"我的修改",保留"别人的修改"。鼠标右键点击Theirs框的相应行,点击"Use this text block"。
  • 同时保留"我的修改"和"别人的修改",并将"我的修改" 放在前面。鼠标右键点击Mine框的相应行,点击"Use text block from mine before theirs"。
  • 同时保留"我的修改"和"别人的修改",并将"别人的修改"放在前面。鼠标右键点击Mine框的相应行,点击"Use text block from theirs before mine"。

合并完成,Ctrl+S存盘,退出。

然后,在资源管理器中,选择冲突文件,鼠标右键菜单选择"Resolved",标记冲突已解决。系统会自动删除因冲突而新建的文件。此时,就可以继续进行commit操作了。

add(增加)操作

增加新文件或目录,要先用add,再commit

在资源管理器中,选择新增的目录或文件,鼠标右键菜单选择"Add"。

提示增加的文件。点"ok"继续。结束点"ok"。

Saturday, November 21, 2009

编写可移植C/C++程序的要点

文章出处:http://www.limodev.cn/blog
作者联系方式:李先静 <xianjimli at hotmail dot com>
 

以前做过两年C++程序移植工作,从Win32平台移植到Linux平台。大约有上百万行C/C++代码,历时一年多。在开发Win32版本时,已经强调了程序的可植性,无奈Win32团队里对Linux精通的人比较少,很多问题没有想到,直到后来移植工作开始时,才发现移植并非像想的那样简单。

后来,我发现大家对移植工程师都比较轻视,不管是从工资待遇还是管理层的态度来看都是这样。他们往往认为,你们不过是把别人实现好的东西移植过去罢了,你老老实实,按步就班去做就行了,根本不需要丝毫创意。事实并非如此,特别是对于大项目,其中遇到的问题和困难可谓一言难尽。比如前面提到的那个项目,虽然过去好几年了,很多问题我仍然记忆犹新。

这里总结一些经验吧,这些经验,无一不是经过大量汗水换来的,有的引起的BUG甚至耗费数周时间才查出来。写出来,供类似的项目参考,不用再走这些弯路。

1.分层设计,隔离平台相关的代码。就像可测试性一样,可移植性也要从设计抓起。一般来说,最上层和最下层都不具有良好的可移植性。最上层是GUI,大多数GUI都不是跨平台的,如Win32 SDK和MFC。最下层是操作系统API,大多部分操作系统API都是专用的。

如果这两层的代码散布在整个软件中,那么这个软件的可植性将非常的差,这是不言自明的。那么如何避免这种情况呢?当然是分层设计了:

最底层采用Adapter模式,把不同操作系统的API封装成一套统一的接口。至于封装成类还是封装成函数,要看你采用的C还是C++写的程序了。这看起来很简单,其实不尽然(看完整篇文章后你会明白的),它将耗去你大量的时间去编写代码,去测试它们。采用现存的程序库,是明智的做法,有很多这样的库,比如,C库有glib(GNOME的基础类),C++库有ACE(ADAPTIVE Communication Environment)等等,在开发第一个平台时就采用这些库,可以大大减少移植的工作量。

最上层采用MVC模型,分离界面表现与内部逻辑代码。把大部分代码放到内部逻辑里面,界面仅仅是显示和接收输入,即使要换一套GUI,工作量也不大。这同时也是提高可测试性的手段之一,当然还有其它一些附加好处。所以即使你采用QT或者GTK+等跨平台的GUI设计软件界面,分离界面表现与内部逻辑也是非常有用的。

若做到了以上两点,程序的可移植性基本上有保障了,其它的只是技术细节问题。

2.事先熟悉各目标平台,合理抽象底层功能。这一点是建立在分层设计之上的,大多数底层函数,像线程、同步机制和IPC机制等等,不同平台提供的函数,几乎是一一对应的,封装这些函数很简单,实现Adapter的工作几乎只是体力活。然而,对于一些比较特殊的应用,如图形组件本身,就拿GTK+来说吧,基于X Window的功能和基于Win32的功能,两者差巨大,除了窗口、事件等基本概念外,几乎没有什么相同的,如果不事先了解各个平台的特性,在设计时就精心考虑的话,抽象出来的抽口在另外一个平台几乎无法实现。

3.尽量使用标准C/C++函数。大多数平台都会实现POSIX(Portable Operating System Interface)规定的函数,但这些函数较原生(Native) 函数来说,性能上的表现可能较次一些,用起来也不如原生函数方便。但是,最好不要贪图这种便宜而使用原生函数函数,否则搬起的石头最终会轧到自己的脚。比如,文件操作就用fopen之类的函数,而不要用CreateFile之类的函数等。

4.尽量不要使用C/C++新标准里出现的特性。并不是所有的编译器都支持这些特性,像VC就不支持C99里面要求的可变参数的宏,VC对一些模板特性的支持也不全面。为了安全起见,这方面不要太激进了。

5.尽量不要使用C/C++标准里没有明确规定的特性。比如你有多个动态库,每个动态库都有全局对象,而且这些全局对象的构造还有依赖关系,那你迟早会遇到麻烦的,这些全局对象构造的先后顺序在标准里是没有规定的。在一个平台上运行正确,在另外一个平台上可能莫明其妙的死机,最终还是要对程序作大量修改。

6.尽量不要使用准标准函数。有些函数大多数平台上都有,它们使用得太广泛了,以至于大家都把它们当成标准了,比如atoi(把字符串转换成整数)、strdup(克隆字符串)、alloca(在栈分配自动内存)等等。不怕一万,就怕万一,除非明白你在做什么,否则还是别碰它们为好。

7.注意标准函数的细节。也许你不相信,即使是标准函数,抛开内部实现不论,就其外在表现的差异也有时令人惊讶。这里略举几个例子:

*. int accept(int s, struct sockaddr *addr, socklen_t *addrlen);addr/ addrlen本来是输出参数,如果是C++程序员,不管怎么样,你已经习惯于初始化所有的变量,不会有问题。如果是C程序员,就难说了,若没有初始化它们,程序可能莫名其妙的crash,而你做梦也怀疑不到它头它。这在Win32下没问题,在Linux下才会出现。

*. int snprintf(char *str, size_t size, const char *format, …);第二个参数size,在Win32下不包括空字符在内,在Linux下包括空字符,这一个字符的差异,也可能让你耗上几个小时。

*. int stat(const char *file_name, struct stat *buf);这个函数本身没有问题,问题出在结构stat上,st_ctime在Win32下代表创建(create)时间,在Linux下代表最后修改 (change)时间。

*. FILE *fopen(const char *path, const char *mode);在读取二进制文件,没有什么问题。在读取文本文件可要小心,Win32下自动预处理,读出来的内容与文件实际都长度不一样,在Linux则没有问题。

8.小心数据标准数据类型。不少人已经吃过int类型由16位转变成32位带来的苦头,这已经是陈年往事了,这里且不谈。你可知道char在有的系统上是有符号的,在有的系统是无符号的吗?你可知道wchar_t在Win32下是16位的,在Linux 下是32位的吗?你可知道有符号的1bit的位域,取值是0和-1而不是0和1吗?这些貌合神离的东东,端的是神出鬼没,一不小心着了它的道。

9.最好不要使用平台独有的特性。比如Win32下DLL可以提供一个DllMain函数,在特定的时间,操作系统的Loader会自动调用这个函数。这类功能很好用,但最好不要用,目标平台可不能保证有这种功能。

10.最好不要使用编译器特有的特性。现代的编译器都做很人性化,考虑得很周到,一些功能用起非常方便。像在VC里,你要实现线程局部存储,你都不调用TlsGetValue /Tls TlsSetValue之类的函数,在变量前加一个__declspec( thread )就行了,然而尽管在pthread里有类似的功能,却不能按这种方式实现,所以无法移植到Linux下。同样gcc也有很多扩展,是在VC或者其它编译器里所没有的。

11.注意平台的特性。比如:

*. 在Win32下的DLL里面,除非明确指明为export的函数外,其它函数对外都是不可见的。而在Linux下,所有的非static的全局变量和函数,对外全部是可见的。这要特别小心,同名函数引起的问题,让你查上两天也不为过。

*. 目录分隔符,在Win32下用'\\',在Linux下用'/'。

*. 文本文件换行符,在Win32下用'\r\n',在Linux下用'\n',在MacOS下用'\r'。

*. 字节顺序(大端/小端),不同硬件平台的字节顺序可能不一样。

*. 字节对齐,在有的平台(如x86)上,字节不对齐,无非速度慢一点,而有的平台(如arm)上,它完全用错误的方式去读取数据,而且不会给你一点提示。若出问题,可能让你一点头绪都没有。

12.最好清楚不同平台的资源限制。想必你还记得DOS下同时打开的文件个数限制在几十个的情形吧,如今操作系统的功能已经强大多了,但是并非没有限制。比如Linux下的共享内存默认的最大值是4M。若你对目标平台常见的资源限制了然于胸,可能有很大的帮助,一些问题很容易定位。

可移植性的问题决不限于以上几种,一方面,即使以前遇到过的问题,部份已经忘记了。另外一方面,还有很多未知的问题,根本没有遇到过。这里算是抛砖引玉吧,请大家补充。

//////////////////
2009.9.7号补充
1: linux下文件名大小写敏感,windows下不敏感
2:不要暴露api的平台相关特性。
3:注意 4.0/5.0的结果是以double精度存储的,如果 float a = 4.0/5.0会带来精度损失。

Some notes on floating point programming with UNIX or Linux

This is not a big page but some things that you should know are actually quite obscure and rarely documented.

Exceptions

Try this:
int i=1/0;

This generates a Floating Point Exception signal, SIGFPE, which is as things should be. Now try this: double i=1/0.0;

And nothing happens! If you now try to print i (printf("%f", i);), it outputs 'inf'. This is decidely Windowsesque, reminiscent of the Visual Basic 'on error resume next' which allows scripts with errors to continue unfazed.

The same happens with double i=sqrt(-1.0) except that this is numerically represented as 'nan', which stands for Not a Number.

I'm unsure why this behaviour is the ISO C mandated default, but such is the case.

The problem

The problem is that many of these errors tend to pass unnoticed, but if you are trying to do some serious calculations, these may be badly tainted by partially invalid results. Infinities can also vanish, for example:
double i=1/0.0;
double j=10.0/i;
printf("%f\n", j);
This prints out 0.00000, which is decidedly bogus.

It is slow too!

On Intel processors, everytime you incur a NaN, the processor stalls badly. A small program which suffered a lot from invalid numbers ran in 0.5 seconds on most Athlon processors and took almost 2 minutes on a Xeon.

Restoring sanity

Under Linux, the following works:

#include <fenv.h>
feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW );
Be sure to compile with -lm. On other operating systems not supporting feenableexcept() I think you will have to use a two step process involving fegetexceptflag() and fesetexceptflag(), consult their manpages.

Most floating point exceptions now cause a SIGFPE. There are functions available to determine from the signal handler which exception occurred.

(note that some simple experiments may not immediately cause a SIGFPE, for example, double d=1/1.0 is typically calculated at compile time)

Other exceptions

C99 defines two additional exceptions, FE_UNDERFLOW and FE_INEXACT, FE_UNDERFLOW occurs when the answer of a calculation is indistinguishable from zero, which in some contexts may be considered bad news.

The other is a quaint one, FE_INEXACT. This one happens whenever a result cannot be exactly represented by the chosen floating point encoding, which happens quite a lot, for example when calculating sqrt(2). Probably not very useful.

Optimization

Quite a lot can be written about this, but I happily refer the reader to Agner Fog's Pentium Optimization Guide.

In short, remember the following:

  • Multiplication is always faster than division, so if at all possible rewrite your math to multiply as much as possible
  • Most CPUs can do multiple calculations at once, but only if these do not depend on eachother. So when adding a list of numbers, it makes sens to separately account for the odd and even indexed numbers, to break the 'dependency chain', and in the end add up the odd and even results.
  • float is way faster than double
 

half edge

Introduction


A common way to represent a polygon mesh is a shared list of vertices and a list of faces storing pointers for its vertices. This representation is both convenient and efficient for many purposes, however in some domains it proves ineffective.

Mesh simplification, for example, often requires collapsing an edge into a single vertex. This operation requires deleting the faces bordering the edge and updating the faces which shared the vertices at end points of the edge. This type of polygonal "surgery" requires us to discover adjaceny relationships between components of the mesh, such as the faces and the vertices. While we can certainly implement these operations on the simple mesh representation mentioned above, they will most likely be costly; many will require a search through the entire list of faces or vertices, or possibly even both.

Other types of adjacency queries on a polygon mesh include:
  • Which faces use this vertex?
  • Which edges use this vertex?
  • Which faces border this edge?
  • Which edges border this face?
  • Which faces are adjacent to this face?
  • To implement these types of adjacency queries efficiently, more sophisticated boundary representations (b-reps) have been developed which explicitly model the vertices, edges, and faces of the mesh with additional adjacency information stored inside.

    One of the most common of these types of representations is the winged-edge data structure where edges are augmented with pointers to the two vertices they touch, the two faces bordering them, and pointers to four of the edges which emanate from the end points. This structure allows us to determine which faces or vertices border an edge in constant time, however other types of queries can require more expensive processing.

    The half-edge data structure is a slightly more sophisticated b-rep which allows all of the queries listed above (as well as others) to be performed in constant time (*). In addition, even though we are including adjacency information in the faces, vertices and edges, their size remains fixed (no dynamic arrays are used) as well as reasonably compact.

    These properties make the half-edge data structure an excellent choice for many applications, however it is only capable of representing manifold surfaces, which in some cases can prove prohibitive. Mathematically defined, a manifold is a surface where every point is surrounded by a small area which has the topology of a disc. For the purpose of a polygon mesh, this means that every edge is bordered by exactly two faces; t-junctions, internal polygons, and breaks in the mesh are not allowed.

    (*) More precisely, constant time per piece of information gathered. For instance when querying all edges adjacent to a vertex, the operation will be linear in the number of edges adjacent to the vertex, but constant time per-edge.


    Structure


    The half-edge data structure is called that because instead of storing the edges of the mesh, we store half-edges. As the name implies, a half-edge is a half of an edge and is constructed by splitting an edge down its length. We'll call the two half-edges that make up an edge a pair. Half-edges are directed and the two edges of a pair have opposite directions.

    The diagram below shows a small section of a half-edge representation of a triangle mesh. The yellow dots are the vertices of the mesh and the light blue bars are the half-edges. The arrows in the diagram represent pointers, although in order to keep the diagram from getting too cluttered, some of them have been ommited.



    As you can see in the diagram, the half-edges that border a face form a circular linked list around its perimeter. This list can either be oriented clockwise or counter-clockwise around the face just as long as the same convention is used throughout. Each of the half-edges in the loop stores a pointer to the face it borders (not shown in the diagram), the vertex at its end point (also not shown) and a pointer to its pair. It might look something like this in C:

         struct HE_edge     {

    HE_vert* vert; // vertex at the end of the half-edge HE_edge* pair; // oppositely oriented adjacent half-edge HE_face* face; // face the half-edge borders HE_edge* next; // next half-edge around the face };


    Vertices in the half-edge data structure store their x, y, and z position as well as a pointer to exactly one of the half-edges which uses the vertex as its starting point. At any given vertex there will be more than one half-edge we could choose for this, but we only need one and it doesn't matter which one it is. We'll see why later on when the querying methods are explained. In C the vertex structure looks like this:

         struct HE_vert     {

    float x; float y; float z;

    HE_edge* edge; // one of the half-edges emantating from the vertex };


    For a bare-bones version of the half-edge data structure, a face only needs to store a pointer to one of the half-edges which borders it. In a more practical implementation we'd probably store information about textures, normals, etc. in the faces as well. The half-edge pointer in the face is similar to the pointer in the vertex structure in that although there are multiple half-edges bordering each face, we only need to store one of them, and it doesn't matter which one. Here's the face structure in C:

         struct HE_face     {

    HE_edge* edge; // one of the half-edges bordering the face };


    Adjacency Queries


    The answers to most adjacency queries are stored directly in the data structures for the edges, vertices and faces. For example, the faces or vertices which border a half-edge can easily be found like this:

         HE_vert* vert1 = edge->vert;     HE_vert* vert2 = edge->pair->vert;

    HE_face* face1 = edge->face; HE_face* face2 = edge->pair->face;


    A slightly more complex example is iterating over the half edges adjacent to a face. Since the half-edges around a face form a circular linked list, and the face structure stores a pointer to one of these half-edges, we do it like this:

          HE_edge* edge = face->edge;

    do {

    // do something with edge edge = edge->next; } while (edge != face->edge);


    Similarly, we might be interested in iterating over the edges or faces which are adjacent to a particular vertex. Referring back to the diagram, you may see that in addition to the circular linked lists around the borders of the faces, the pointers also form loops around the vertices. The iterating process is the same for discovering the adjacent edges or faces to a vertex; here it is in C:

          HE_edge* edge = vert->edge;

    do {

    // do something with edge, edge->pair or edge->face edge = edge->pair->next;

    } while (edge != vert->edge);


    Note that in these iterating examples checks for null pointers are not included. This is because of the restriction on the surface being manifold; in order for this requirement to be fulfilled, all of the pointers must be valid.

    Other adjacency relationships can be quickly found by following these examples.
     

    Thursday, November 19, 2009

    English skill for programmer

    卷首语:"英语"不需要专业,因为它只是工具
    ......


    有时候如果应聘到了一个有外资背景的公司或者这个公司的很多人都有海外或外资工作背景时,你也许还会用到一些日常工作交流时候的词汇。
    比如我们看一下某主管开会时的发言:

            小王,请你尽快"Push"一下这件事,按照前期咱们定下来的"Plan"来"follow"这个"case",每一个"Milestone"都要 "Share"出来,你负责的这块工作要充分的"Open",明天最好和客户做一个"Conference"能够"Face to face"的交流一下。
            小李,你的那个"Project"最近有些"Delay"了,这么多"Resource"都分配给你了,还分配给你了那么多"Part time",作为一个"PM"你应该知道目前这个"Cost"恐怕"Cover"不住这个项目了,你要尽快完成。
            最近"Marketing"那边对我们"Team"的要求比较紧,"Sales"他们的业绩也上来了,咱们作为技术部门要坚决做好"Product"的后盾。


    请注意,这并不是一个笑话,而是在某些公司每天都在发生的一个最最普通的一个部门会议。如果你对这些词汇不明白,恐怕这个会议开下来都不知道领导说的是什么。

    翻译一下:
          小王,请你尽快"推动"一下这件事,按照前期咱们定下来的"计划"来"跟踪"这个"事情",每一个"里程碑"都要"共享"出来,你负责的这块工作要充分的"开放给大家",明天最好和客户做一个"讨论会"能够"面对面"的交流一下。
          小李,你的那个"项目"最近有些"延迟了"了,这么多"资源"都分配给你了,还分配给你了那么多"临时员工",作为一个"项目经理"你应该知道目前这个"成本"恐怕"包"不住这个项目了,你要尽快完成。
          最近"市场部门"那边对我们"团队"的要求比较紧,"销售人员"他们的业绩也上来了,咱们作为技术部门要坚决做好"产品开发"的后盾。


    很有意思吧,经常能在公司中看到喜欢中英文混说的领导。要么本身这个企业就是外企,要么这个领导曾经在外企工作,或者本身就觉得这样说话很酷,但不管是因为什么原因令其进行中英文混说,我们作为程序员,在开会的时候也不能"大眼瞪小眼"吧!
          因此,我们应该尽可能熟悉这些英语词汇,以备不时之需。我们下面就总结一下,在公司中经常会用到的一些单词都是什么意思,以及何时能够用得上。



    几个开会的时候最容易出现的单词

    Conference:讨论会,碰头会议的意思
          例如,有时候领导会说"咱们Call一个Conference吧",这个的意思应该是一个电话会议,或者视频会议。
    Follow:跟踪
          例如,一般会说那个Case你follow一下吧,这就是说让你跟踪一下这个事情。
    Team:
          是团队的意思,团队的主管一般叫Team Leader,一个Team可以大也可以小,一个项目小组可以叫一个Team,一个部门也可以叫做一个Team,有时候一个公司的高层领导团队也可以叫做是一个Team。
    Policy:政策或者是策略
          很多东西都可以制定Policy,销售的Policy,价格的Policy,网络的Policy都可以。
    Open:打开的、开放的
          有时候当成一种状态来说,比如你的项目是不是Open的呢?这个的意思是说,你是不是非常听不进去别人的意见闭门造车呢?
    Share:共享
          例如,把你的文档Share一下吧,有时候也说把你的想法Share一下吧。
    Plan:计划、规划
          例如,你有什么Plan告诉我一下,或者说,你在这件事请开始前是否已经制订了详细的Plan?Plan是每一件事的行动方案和地图。
    Milestone:里程碑、阶段
          例如,请你把每一个Milestone共享出来,就是说让每一个人都知道你项目的进度状况。Milestone就是每一个进展阶段的结束。
    Product:产品
          产品就是一个公司的用于销售而生产的物品,Product有时候也可以代表一个部门,比如"产品部"。
    Project:项目
          一般项目是需要在公司立项的,如果没有立项一般都不能称作一个正式的项目,在立项以后每一个项目都会任命一个项目经理作为这个项目的总负责人,项目经理的英文简称是PM。
    Boss:老板
          我们有时候一提到Boss总是想到的是这个公司的实际控股人,也就是公司里最大的那个领导,其实不尽然,这里面所说的老板并不是整个公司的老板,而指得是你的上级,一般将你的上级也叫做Boss。
    Close:关闭
            Close有时候描述某些事情的状态,比如说,"这个事情已经Close了",意思是说这件事情已经了结了,这个和"finish"的意思是不一样的,finish是完成了,而Close是关闭了。
    Manager:经理
            到了工作单位以后,你会发现在一个公司中有无数的Manager,几乎每一个人都可以叫做Manager,大大小小的Manager有很多,但却都不是领导,比如,负责采购的原来叫采购员,现在叫采购经理,负责销售的原来叫销售员,现在叫销售经理,客户服务的原来叫客户服务人员,现在叫客户经理,等等。
    Delay:延迟了
          Delay也是一种状态,这个状态一定是和一个Plan相比较的,在Plan中设定了每一个Milestone的时间点,而在相应的时间点上没有完成那个Milestone的目标,那么说明这个项目Delay了。
    Schedule:时间表
          有时候在规范每一个人在项目中在不同时间段应该完成的事情,可以编制一个Schedule的Excel文件,发给每一个参与项目的人员
    Update:更新一下
    Push:推动
          比如,你Push这一下这件事,就是推动一下。
    Solution:解决方案
          有时候说,给用户提供一个Total solution的意思是,全面的解决方案。
    Announce:宣布
          比如,有时候说,把你们的想法通过Email Announce出来,这就是说发一个群发邮件,让所有人都知道你所要表达的某些计划等等。
    Interview:原意是接见会见的意思,但是现在面试也是这个。
    Resource:资源
    Review:检查一下或者回顾一下

    几个和软件开发相关的单词

    API:Application Programming Interface 应用编程接口
          比如,两个本来互相没有联系的系统需要数据共享,就需要开发API作为接口。
    Coding:编码工作
          有时候将正式开始编码工作称作"Coding",听起来似乎怪怪的,但实际上就是敲代码。
    Document:文档
    WebBase:Web应用程序
          "WebBase"从单词字面上看就是以Web为基础的意思,其实就是所谓的"B/S"结构的程序,有时候如果你和不懂技术的人交流说"B/S"他们不懂,你就说"WebBase"他们一定懂。
    Face to face:面对面
    Hand by hand:手把手
    Step by Step:一步一步的
    Quality:质量
          "Quality"可以说产品的质量,也可以说是网络通信的"Quality"等。
    On-line:在线的
          有时候所谓的"On-line的客户"并不是说他们现在就在线上连接着网络或者服务器,而有时候是指这些客户是我们的正式客户。
    Handbook:手册
    License:许可证
          经常听到"购买几个License"这样的话,"License"意思就是授权许可,有时候即使这个软件可以正常安装使用也是非法的,因为没有购买 "License",只有购买了"License"才可以合法使用,也就是所谓的"正版"。对于软件而言,有时候"License"并没有加密措施,完全是一种自觉行为。对于网络版软件而言,每一个客户端的使用都需要购买相应的"License"。
    On-site:现场服务
          现场服务我们称作"On-site"服务,需要派工程师到用户的现场实施服务。
    Report:报告
          很多情况下人们把"Report"翻译成"报表",其实"Report"本身即是名词又是动词,作为动词用到的地方也很多,比如,在一个公司中有人问"你report给谁?",这句话的意思是说"你的上级主管是谁"。
    Version:版本

    几个常用的设备名称的单词

    Voice gateway:语音网关
    Router:路由器
    HUB:有时候已经把小的桌面级的集线器和交换机都叫HUB
    Switch:交换机

    几个常用和商务相关的单词

    Order:订单
    Price:价格
    List price:官方报价,往往厂家会给一个折扣价,实际采购设备的价格并不是"List price","List price"仅仅是官方报价。
    Customer:客户
    Partner:合作伙伴
    Billing:计费
    Marketing:市场,有时候也代表市场部门 

    几种职位名称的称呼

    CEO:Chief Executive Officer的简称,首席执行官
    COO:Chief Operating Officer的简称,运营总裁
    CTO:Chief Technology Officer的简称,首席技术官
    Director:总监
    HR:Human resource的简称,人力资源部
    CS:Customer service的简称,客户服务部门
    MIS:公司办公网络和办公设备管理人员
    Teamleader:团队领导
    PM:Project Manager的简称,项目经理
    Sales:销售的,有时候代表销售人员
    Engineer :工程师
    Parttime:临时员工,或者叫兼职工作人员
     
     
    本文来自CSDN博客:http://blog.csdn.net/useway/archive/2009/08/15/4449929.aspx

    学习的革命——杂谈程序员的学习力

    引言:达尔文在进化论中写道"物竞天择,适者生存",达老的观点是:这个世界上能够生存下来的物种,不是身体最强壮的,也不是智商最高的,而是对环境适应能力最强的。很久以前,体型庞大的恐龙没有生存下来,咯屁了;当年和人类智商一样高的猿猴,没进化成功,堕落了;只有人类,从与猿猴一样的造型不断的进化至今,在这个过程中人类不断的去学习,学会取火、制作工具、直立行走……演化至今。不断的学习新的技术,适应环境的变化,并改造环境甚至创造环境,成就了人类的今天。

        在这个竞争日益激烈的社会,在IT行业这个飞速发展的领域,做为程序员的我们,能否适应这个环境,甚至成为这个环境的主宰,学习力是我们得以生存和更好的生活的关键。而计算机技术日新月异的变化,也要求我们程序员要不断的学习,不断的充实自己。时代光华曾经有一句口号:"知识改变命运学习成就未来",此话有道啊。很多企业招聘时,也都特别对新人提出一个要求:具备良好的学习能力。
        搞技术是一个很累的事情,很多程序员都这样感慨,初学时觉得不会的东西太多,做了几年后还是感觉学无止境,即便是一个N年的老鸟,也还要不断充电,否则没两年恐怕就没法在这个圈子里面混了。很多朋友都在疲于奔命,哀号学习之苦。
        有一个业界广泛流传的故事:一富婆(估计是体重200斤以上、脸上的粉刮下来可以包二三十个饺子、说话眼睛看天花板的老女人)去夜总会找乐子,殷勤的老板娘挑了几个帅小伙,富婆不满意;又挑了几个壮小伙,富婆还不满意;老板娘问富婆到底想要什么样的啊,富婆说"体力好、精力旺、能加班、能熬夜、随叫随到、吃苦耐劳",老板娘一下乐了……张口大喊:"机房里搞程序,出来接客!"
        可见程序员平日的工作恐怕就已经很繁忙了……不过就像我一直坚定的认为程序员的形象不应该是"工作狂人、缺少情趣、蓬头垢面、衣着杂乱、身有异味"一样,我们要管理好我们的时间,时间就像海绵里的水,马克思告诉俺们,要挤就一定会有的,工作可以满足我们的现在,学习才可以成就我们的未来。本文旨在根据笔者的经验,给亲爱的读者们一点点学习的建议。

    第一,学习的目标管理:

        怎么学习是个方法问题,我们稍后再谈,但是在此之前想要搞明白我们要学习什么,这是个目标问题。很多程序员没有明确的目标,不知道自己最终要的是一种什么样的生活,也不清楚自己三年以后五年以后十年以后的人生目标是什么,甚至连三个月半年或是一年内的短期目标也没有,那自然也就无从谈起明确的学习目标。
    曾经看过这样一个故事,在美国的贫民区,有一个十几岁的小孩,一直梦想着有一天可以成为美国总统,于是他开始构思:要成为总统,就必须先做州长;要做州长,就要有钱去拉选票;要想有钱,就得娶一富家千金;要娶千金,做影坛明星最合适不过;为做明星又得有魅力,于是他开始学习健美,亲爱的看官,您觉得这个小孩的梦想会实现吗?您是不是认为这就是传说中的"扯犊子",美国式白日梦……
        不过,这是一个真实的故事,后来,这个小孩果然非池中之物,练习健美得了N个国内国际的健美大赛冠军,甚至还出了几本健美健身类的书;后来打入好莱坞拍了很多部很牛X的电影成了国际明星;坚持多年的感情终于娶到了富家千金,这个千金大有来头,就是被枪杀的美国总统肯尼迪的侄女;再后来息影从政,如愿当选了美国加州州长。现在,他就差没把小布什赶出白宫了,是的,相信您应该也猜到了,他就是:阿诺德·施瓦辛格。
    这个真实的故事告诉我们,只要有梦想,做好规划,奋力去拼搏,一切皆有可能(此处为支持国货,插播李宁公司广告)。
        个人建议,如果您是一个新丁,刚入行的几年,多学技术;如果您已经变成一个大手,那么可以学学管理或者市场方面的知识。新手最重要的是技术的累积,毕竟想成为项目经理或是技术总监等大鸟,第一个前提还是技术要过硬,否则无法服众,技术永远都是程序员的第一看家本领;在中国这个环境,很少有程序员能做到35岁,一般到了30岁左右至少要前进一步——做个主管,这时可能更多需要的是带领技术团队的能力、与客户沟通的能力等等,如果想拉大旗自己干,则更是如此。
        但是,诚如施瓦辛格的故事一样,我们要有一个规划,至少要确定自己的长期目标和短期目标,并列出计划,努力行动。比如,我们制订出三年内的目标,假设您是一个新手,您是要强化自己的英文能力,学习英语;或是要增加学历的厚度,读个研究生;还是要狠K一项新的技能,比如PHP ……总之,这三年内我们要定一下学习的目标,可能第一年我们达到阅读计算机英语完全没有问题,第二年我们要K下来PHP ,在这三年中我们要努力考取研究生并读完获得学历。总之,我们要有一个计划,然后进行分解,如果我们要搞定英语阅读能力,我们怎么办?12个月,48周,365天,每个月达到什么程度,每周完成多少任务,每天做哪些学习(假设是每天背下来15个英文单词,阅读千字左右的文档3篇)。那么,我们的目标就落实了,计划就落地了,目标才会随着每天每周每月的过去而逐步实现。
        要立长志,不要常立志。随波逐流,撞大运,听天命,永远成为不了高手,毕竟天上没那么多馅饼掉下来,就算掉下来也未必正好砸咱脑袋上不是吗。

    第二,学习的时间管理

        程序员自己的时间,似乎少的可怜,有时我们要加班加点,有时我们要封闭开发,还有时客户请吃饭我们喝大了……所以很多程序员说,忙得连谈女朋友的时间都没有,可是,生活不会因为这些借口而宽容我们。房价依然会高到离谱,女朋友依然会抱怨没人陪伴,通货膨胀也不会就此停止……生活依然要继续,我们不能停下脚步,不能停下学习进步的脚步。
        对此,我有两个看法,第一个看法,让我们来看一个小故事吧——
        一位管理专家在一群学生面前,拿出一个广口瓶放在桌上,同时拿出了几十个拳头大小的石块,一个个放进瓶中,当石块放满整个瓶子后,专家问:"瓶子装满了吗?"
    同学们回答:"装满了!"
        "真的吗?"专家再拿出一桶碎石,取出一把倒入瓶中,再把瓶子摇一摇,让碎石填入石块中的缝隙,"瓶子装满了吗?"。
        有位同学回答:"也许没有"。
        "很好!"专家又拿出一桶沙子倒进瓶中,充满了石块所留下的空间,然后再问:"瓶子装满了吗?"
        全班大声回应:"没有!"
        "非常好!"这次专家拿出一壶水,注入瓶中,直到水满至瓶口。专家看着全班同学问道:"这个展示的重点是什么?"
        一位勇敢的学生举手说:"无论你的日程排得有多满,只要尽全力安排,还是可以安排很多事情!"
        专家回答:"错!",重点是——
        "如果你不先把石块放进去,就永远也放不进去了!"
        在生活中大家有没有发现,我们很多很多的时间浪费在了无关紧要的小事上,而我们的目标是重要的紧急的事情,可惜,它却没有获得最多的时间去处理。大事法则告诉我们,做事要有条理,不要抱怨没有时间,先看看,要做的事情是不是每一件都是重要的或者紧急的,不要再让琐碎的小事浪费自己的生命了。
        我的第二个看法:学会化零为整,尽量把时间用在重要和紧急的事情上,但是我们仍然会有大把时间是零散的。
    我曾经听过一个讲座,叫《做自己想做的人》,主讲人讲了一个自己的时间管理的方法,就是:随时随地都可以休息。牛啊,他可以把所有的时间有效利用,虽然他也很忙,但是如果今天公司组织出去卡拉OK ,他也可以在包厢嘈杂的声音中睡着(我当年也练成了一个本领,就是可以在公车或地铁上抓住扶手,头靠在胳膊上,三十秒入睡)。即便有一点小小的时间,那怕在等车,那怕在等人,都可以掏出来一本书看,这就时间管理的观念。
        在时间管理上有三个"B"——Bathe洗澡、Bus坐车、Bed睡觉
        有多少人,在洗澡的时候在发呆在胡思乱想;有多少人,在坐车的时候在东张西望;有多少人,在睡觉前在数绵羊或者是大脑一片空白……那么,把这些时间好好利用起来吧,我们可不可以在洗澡的时候想想今天写的一段代码为什么执行报错;我们可不可以在清晨坐车的时候看看技术书籍或者计划一下一天的工作;我们可不可以在睡觉前想一下今天都做了什么事情有没有什么经验教训要总结……如果这些零散的时间我们都能利用起来,积少成多,您会发现,有一天,会改变我们的生活。

    第三,学习的方法问题

        凡事要讲究方法,才能事半功倍。愚公移山固然可贵,可惜要"子子孙孙无穷尽也",这玩艺咱来不了……
        就比如今天一个兄弟说想要学习Linux ,问我什么方法最好,那么我可以给出一个选择:首选,找个Linux高手当师傅来带你入门直至出徒;次选,参加一个Linux培训班和老师学习;次次选,买一本Linux书边看边实践;次次次选,在网上搜索资料自学。
        可能各位看官都觉得通过网络学习(比如通过论坛等获取知识的途经)是很好的方法,诚然这是方法之一,但是如果想最快最有效的学习Linux ,对于一个初学者,首选当然是有师傅来指导,有过来人讲述亲身经验,可以让他走过的弯路我们不再走,他的经验教训我们拿来就用,这是最快的一种方法;如果不具备这样的机会,条件允许可以参加个培训班,授课的老师会总结自己的体会和经验,系统化的把知识讲给我们听,这种学习速度也比较快;如果资金有困难,那么强烈建议至少要买一本书,毕竟好的书是作者的心得体会的总结,看一本书可以让我们学习更条理化;当然如果您真是一毛不拔,书都不想买,只是想通过网络学习,那么我只能说这并不适合初学者,因为网上知识太乱太杂,老鸟去获取是一种很好的手段,可是新手往往无法分辨,效果自然惨不忍睹。这就是方法的问题。
        再比如,假设看官您是刚刚升任公司项目部经理,首先面临的一个最大的问题就是,如何在竞标中向客户做演示讲解,这对于平时埋头做技术沉默寡言的您是否是个挑战?没办法了,回家对着四面墙狂练吧,但是练习也要有方法,一方面可以从网上找些产品演示或演讲技巧的视频教程或者买相关的书籍来看,或者向前辈讨教下,这是必要的;另一方面自己练习时,要有方法,比如可以使用电脑的录音功能录制下来自己练习的过程,回过头来,自己去听自己的讲解是否满意,然后总结什么地方有问题,依次循环往复,相信会受益最多效果最好进步最快,这就是方法了。
        不为失败找借口,要为成功找方法,方法是让我们的时间更有效的重要手段,比如笔者每天晚上都会总结好第二天要做的事项,一个一个列在日程表中,第二天,做完一个划掉一个,虽然同样是做事情,但是这种成就感是让人做事非常愉快的,而且事情也不容易遗漏,这也是一种方法。
        "黑猫白猫抓到耗子就是好猫",可是我们总不能让一只猫搞了一个月才抓到耗子,时间不等人,找到适合自己的学习方法,是达成目标的关键。我曾经认识一位学习Linux的新人,成天捧着一本《Linux命令大全》疯狂的看书敲命令,我真不忍心打击他,因为Linux现在至少有两三千个命令,每个命令平均有二三十个选项,要敲到什么时候呢……何况这些命令和选项,我使用Linux七年了,感觉也不过用到其中十分之一都不到,常用的并没有那么多……可惜啊,时间就这样别浪费了,这就是方法的错误。

        本文到此,也该结束了,本文名为《学习的革命》,实则是作者作为LAMP兄弟连标题党一员的通病,内容没有那么"革命",鲁迅先生讲我们要革了谁的命,我想,作为程序员来讲,先革了自己的命吧,如果过去您在懒惰您在懈怠,如果过去您在为学习找借口想托词,先革了自己的命,改变,从新来过。
        如果还不清楚要怎么开始,那么给您个建议,先搞明白这三个事情——
           第一、为何学习
           第二、学习什么 
           第三、怎么学习

        我坚信任何一个人都渴望成功,任何一个人都期望过自己想过的生活,不付出辛勤的汗水,这是不可能实现的……天上的馅饼,如同程序员中的美女一样,总是很少很少的,与其白日发梦,不如踏踏实实的学习和工作,不是吗?**教导过我们,好好学习,才能天天向上。

        莫等闲,白了少年头,空悲切,与君共勉。
     
     
    转载自"李明的笔记",在此谢过!

    Wednesday, November 18, 2009

    自己还真是不行啊

    不能总怪老板给的工作不合理,不能总怪老板要求的工具不顺手...今天总算是对自己有点了解:你不是一个好的程序员,甚至可以说是一个很差的程序员!对软件工程的理解和应用几乎是零,从来没有写过一行有拓展性和复用性的代码,遇到问题了就东拼西凑,想办法让他works,从来没有想过提高自己,让自己写点优雅的代码!这都做不好,就更别提什么效率了,嵌套循环,无聊的数据复制和毫无节制的开辟数据空间,这怎么可能有好的效率?对于图形编程,简直就跟白痴一样,以前的课肯定是白上了,现在想用它来指导学习和工作根本就不可能!所以不要提你曾经学过图形学,编过OpenGL程序...简直就是扯淡,你狗屁不通!总是在发呆不知道在干什么,邮件不能按时回复,布置的事情不能按时完成,这些都跟自己的懒惰和怕事分不开,要是不能超越,那就肯定是废了!最后是英语问题,简直是不堪入耳,听不懂说不清么!
    这些小事情都干不好,要你何用?臭皮囊...我承认了!

    Sunday, November 15, 2009

    深刻理解Linux进程间通信

    一个大型的应用系统,往往需要众多进程协作,进程(Linux进程概念见附1)间通信的重要性显而易见。本系列文章阐述了 Linux环境下的几种主要进程间通信手段,并针对每个通信手段关键技术环节给出详细实例。为达到阐明问题的目的,本文还对某些通信手段的内部实现机制进行了分析。

    linux 下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的。而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间通信方面的侧重点有所不同。前者对Unix早期的进程间通信手段进行了系统的改进和扩充,形成了 "system V IPC",通信进程局限在单个计算机内;后者则跳过了该限制,形成了基于套接口(socket)的进程间通信机制。Linux则把两者继承了下来,如图示:



    其中,最初Unix IPC包括:管道、FIFO、信号;System V IPC包括:System V消息队列、System V信号灯、System V共享内存区;Posix IPC包括: Posix消息队列、Posix信号灯、Posix共享内存区。有两点需要简单说明一下:1)由于Unix版本的多样性,电子电气工程协会(IEEE)开发了一个独立的Unix标准,这个新的ANSI Unix标准被称为计算机环境的可移植性操作系统界面(PSOIX)。现有大部分Unix和流行版本都是遵循POSIX标准的,而Linux从一开始就遵循POSIX标准;2)BSD并不是没有涉足单机内的进程间通信(socket本身就可以用于单机内的进程间通信)。事实上,很多Unix版本的单机 IPC留有BSD的痕迹,如4.4BSD支持的匿名内存映射、4.3+BSD对可靠信号语义的实现等等。

    图一给出了 linux 所支持的各种IPC手段,在本文接下来的讨论中,为了避免概念上的混淆,在尽可能少提及Unix的各个版本的情况下,所有问题的讨论最终都会归结到 Linux环境下的进程间通信上来。并且,对于Linux所支持通信手段的不同实现版本(如对于共享内存来说,有Posix共享内存区以及System V共享内存区两个实现版本),将主要介绍Posix API。

    linux下进程间通信的几种主要手段简介:

    1. 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;
    2. 信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数);
    3. 报文(Message)队列(消息队列):消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
    4. 共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
    5. 信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
    6. 套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。

    下面将对上述通信机制做具体阐述。

    附1:参考文献[2]中对linux环境下的进程进行了概括说明:

    一般来说,linux下的进程包含以下几个关键要素:

    • 有一段可执行程序;
    • 有专用的系统堆栈空间;
    • 内核中有它的控制块(进程控制块),描述进程所占用的资源,这样,进程才能接受内核的调度;
    • 具有独立的存储空间

    进程和线程有时候并不完全区分,而往往根据上下文理解其含义。

    作者:郑彦兴 (mlinux@163.com)国防科大计算机学院

    linux 进程间通信--共享内存

    作者:郑彦兴 (mlinux@163.com), 国防科大攻读博士学位
     
    共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。
     
    范例1包含两个子程序:map_normalfile1.c及map_normalfile2.c。编译两个程序,可执行文件分别为 map_normalfile1及map_normalfile2。两个程序通过命令行参数指定同一个文件来实现共享内存方式的进程间通信。 map_normalfile2试图打开命令行参数指定的一个普通文件,把该文件映射到进程的地址空间,并对映射后的地址空间进行写操作。 map_normalfile1把命令行参数指定的文件映射到进程地址空间,然后对映射后的地址空间执行读操作。这样,两个进程通过命令行参数指定同一个文件来实现共享内存方式的进程间通信。
     
    /*-------------map_normalfile1.c-----------*/ #include <sys/mman.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> typedef struct{ 	char name[4]; 	int  age; }people; main(int argc, char** argv) // map a normal file as shared mem: { 	int fd,i; 	people *p_map; 	char temp; 	 	fd=open(argv[1],O_CREAT|O_RDWR|O_TRUNC,00777); 	lseek(fd,sizeof(people)*5-1,SEEK_SET); 	write(fd,"",1); 	 	p_map = (people*) mmap( NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0 ); 	close( fd ); 	temp = 'a'; 	for(i=0; i<10; i++) 	{ 		temp += 1; 		memcpy( ( *(p_map+i) ).name, &temp,2 ); 		( *(p_map+i) ).age = 20+i; 	} 	printf(" initialize over \n "); 	sleep(10); 	munmap( p_map, sizeof(people)*10 ); 	printf( "umap ok \n" ); }
    /*-------------map_normalfile2.c-----------*/ #include <sys/mman.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> typedef struct{ 	char name[4]; 	int  age; }people; main(int argc, char** argv)	// map a normal file as shared mem: { 	int fd,i; 	people *p_map; 	fd=open( argv[1],O_CREAT|O_RDWR,00777 ); 	p_map = (people*)mmap(NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); 	for(i = 0;i<10;i++) 	{ 	printf( "name: %s age %d;\n",(*(p_map+i)).name, (*(p_map+i)).age ); 	} 	munmap( p_map,sizeof(people)*10 ); }

    map_normalfile1.c首先定义了一个people数据结构,(在这里采用数据结构的方式是因为,共享内存区的数据往往是有固定格式的,这由通信的各个进程决定,采用结构的方式有普遍代表性)。map_normfile1首先打开或创建一个文件,并把文件的长度设置为5个people 结构大小。然后从mmap()的返回地址开始,设置了10个people结构。然后,进程睡眠10秒钟,等待其他进程映射同一个文件,最后解除映射。

    map_normfile2.c只是简单的映射一个文件,并以people数据结构的格式从mmap()返回的地址处读取10个people结构,并输出读取的值,然后解除映射。

    分别把两个程序编译成可执行文件map_normalfile1和map_normalfile2后,在一个终端上先运行./map_normalfile2 /tmp/test_shm,程序输出结果如下:

    initialize over umap ok
    在map_normalfile1输出initialize over 之后,输出umap ok之前,在另一个终端上运行map_normalfile2 /tmp/test_shm,将会产生如下输出(为了节省空间,输出结果为稍作整理后的结果):
    name: b	age 20;	name: c	age 21;	name: d	age 22;	name: e	age 23;	name: f	age 24; name: g	age 25;	name: h	age 26;	name: I	age 27;	name: j	age 28;	name: k	age 29; 在map_normalfile1 输出umap ok后,运行map_normalfile2则输出如下结果:
    name: b	age 20;	name: c	age 21;	name: d	age 22;	name: e	age 23;	name: f	age 24; name:	age 0;	name:	age 0;	name:	age 0;	name:	age 0;	name:	age 0; 

    从程序的运行结果中可以得出的结论

    1、 最终被映射文件的内容的长度不会超过文件本身的初始大小,即映射不能改变文件的大小;

    2、可以用于进程通信的有效地址空间大小大体上受限于被映射文件的大小,但不完全受限于文件大小。打开文件被截短为5个people结构大小,而在 map_normalfile1中初始化了10个people数据结构,在恰当时候(map_normalfile1输出initialize over 之后,输出umap ok之前)调用map_normalfile2会发现map_normalfile2将输出全部10个people结构的值,后面将给出详细讨论。
    注:在linux中,内存的保护是以页为基本单位的,即使被映射文件只有一个字节大小,内核也会为映射分配一个页面大小的内存。当被映射文件小于一个页面大小时,进程可以对从mmap()返回地址开始的一个页面大小进行访问,而不会出错;但是,如果对一个页面以外的地址空间进行访问,则导致错误发生,后面将进一步描述。因此,可用于进程间通信的有效地址空间大小不会超过文件大小及一个页面大小的和。

    3、文件一旦被映射后,调用mmap()的进程对返回地址的访问是对某一内存区域的访问,暂时脱离了磁盘上文件的影响。所有对mmap()返回地址空间的操作只在内存中有意义,只有在调用了munmap()后或者msync()时,才把内存中的相应内容写回磁盘文件,所写内容仍然不能超过文件的大小。

     

    范例2:父子进程通过匿名映射实现共享内存

    #include <sys/mman.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> typedef struct{ 	char name[4]; 	int  age; }people; main(int argc, char** argv) { 	int i; 	people *p_map; 	char temp; 	p_map=(people*)mmap(NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0); 	if(fork() == 0) 	{ 		sleep(2); 		for(i = 0;i<5;i++) 			printf("child read: the %d people's age is %d\n",i+1,(*(p_map+i)).age); 		(*p_map).age = 100; 		munmap(p_map,sizeof(people)*10); //实际上,进程终止时,会自动解除映射。 		exit(); 	} 	temp = 'a'; 	for(i = 0;i<5;i++) 	{ 		temp += 1; 		memcpy((*(p_map+i)).name, &temp,2); 		(*(p_map+i)).age=20+i; 	} 	sleep(5); 	printf( "parent read: the first people,s age is %d\n",(*p_map).age ); 	printf("umap\n"); 	munmap( p_map,sizeof(people)*10 ); 	printf( "umap ok\n" ); } 

    考察程序的输出结果,体会父子进程匿名共享内存:

    child read: the 1 people's age is 20 child read: the 2 people's age is 21 child read: the 3 people's age is 22 child read: the 4 people's age is 23 child read: the 5 people's age is 24 parent read: the first people,s age is 100 umap umap ok 

    四、对mmap()返回地址的访问

    前面对范例运行结构的讨论中已经提到,linux采用的是页式管理机制。对于用mmap()映射普通文件来说,进程会在自己的地址空间新增一块空间,空间大小由mmap()的len参数指定,注意,进程并不一定能够对全部新增空间都能进行有效访问。进程能够访问的有效地址大小取决于文件被映射部分的大小。简单的说,能够容纳文件被映射部分大小的最少页面个数决定了进程从mmap()返回的地址开始,能够有效访问的地址空间大小。超过这个空间大小,内核会根据超过的严重程度返回发送不同的信号给进程。可用如下图示说明:



    注意:文件被映射部分而不是整个文件决定了进程能够访问的空间大小,另外,如果指定文件的偏移部分,一定要注意为页面大小的整数倍。下面是对进程映射地址空间的访问范例:

    #include <sys/mman.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> typedef struct{ 	char name[4]; 	int  age; }people; main(int argc, char** argv) { 	int fd,i; 	int pagesize,offset; 	people *p_map; 	 	pagesize = sysconf(_SC_PAGESIZE); 	printf("pagesize is %d\n",pagesize); 	fd = open(argv[1],O_CREAT|O_RDWR|O_TRUNC,00777); 	lseek(fd,pagesize*2-100,SEEK_SET); 	write(fd,"",1); 	offset = 0;	//此处offset = 0编译成版本1;offset = pagesize编译成版本2 	p_map = (people*)mmap(NULL,pagesize*3,PROT_READ|PROT_WRITE,MAP_SHARED,fd,offset); 	close(fd); 	 	for(i = 1; i<10; i++) 	{ 		(*(p_map+pagesize/sizeof(people)*i-2)).age = 100; 		printf("access page %d over\n",i); 		(*(p_map+pagesize/sizeof(people)*i-1)).age = 100; 		printf("access page %d edge over, now begin to access page %d\n",i, i+1); 		(*(p_map+pagesize/sizeof(people)*i)).age = 100; 		printf("access page %d over\n",i+1); 	} 	munmap(p_map,sizeof(people)*10); } 

    如程序中所注释的那样,把程序编译成两个版本,两个版本主要体现在文件被映射部分的大小不同。文件的大小介于一个页面与两个页面之间(大小为:pagesize*2-99),版本1的被映射部分是整个文件,版本2的文件被映射部分是文件大小减去一个页面后的剩余部分,不到一个页面大小(大小为:pagesize-99)。程序中试图访问每一个页面边界,两个版本都试图在进程空间中映射pagesize*3的字节数。

    版本1的输出结果如下:

    pagesize is 4096 access page 1 over access page 1 edge over, now begin to access page 2 access page 2 over access page 2 over access page 2 edge over, now begin to access page 3 Bus error		//被映射文件在进程空间中覆盖了两个页面,此时,进程试图访问第三个页面 

    版本2的输出结果如下:

    pagesize is 4096 access page 1 over access page 1 edge over, now begin to access page 2 Bus error		//被映射文件在进程空间中覆盖了一个页面,此时,进程试图访问第二个页面 

    结论:采用系统调用mmap()实现进程间通信是很方便的,在应用层上接口非常简洁。内部实现机制区涉及到了linux存储管理以及文件系统等方面的内容,可以参考一下相关重要数据结构来加深理解。在本专题的后面部分,将介绍系统v共享内存的实现。

    Friday, November 13, 2009

    关于逆向工程[from CSDN]

    很几个朋友留言说这个是逆向工程么,在我看来什么是逆向工程本身是仁者见仁,智者见智的。我参考了一下wikipedia【4】,摘录如下:

    Reverse engineering of software

    The term reverse engineering as applied to software means different things to different people, prompting Chikofsky and Cross to write a paper researching the various uses and defining a taxonomy. From their paper, they state, "Reverse engineering is the process of analyzing a subject system to create representations of the system at a higher level of abstraction."[4] It can also be seen as "going backwards through the development cycle".[5] In this model, the output of the implementation phase (in source code form) is reverse-engineered back to the analysis phase, in an inversion of the traditional waterfall model. Reverse engineering is a process of examination only: the software system under consideration is not modified (which would make it reengineering). Software anti-tamper technology is used to deter both reverse engineering and reengineering of proprietary software and software-powered systems. In practice, two main types of reverse engineering emerge. In the first case, source code is already available for the software, but higher-level aspects of the program, perhaps poorly documented or documented but no longer valid, are discovered. In the second case, there is no source code available for the software, and any efforts towards discovering one possible source code for the software are regarded as reverse engineering. This second usage of the term is the one most people are familiar with. Reverse engineering of software can make use of the clean room design technique to avoid copyright infringement.

    On a related note, black box testing in software engineering has a lot in common with reverse engineering. The tester usually has the API, but their goals are to find bugs and undocumented features by bashing the product from outside.

    Other purposes of reverse engineering include security auditing, removal of copy protection ("cracking"), circumvention of access restrictions often present in consumer electronics, customization of embedded systems (such as engine management systems), in-house repairs or retrofits, enabling of additional features on low-cost "crippled" hardware (such as some graphics card chipsets), or even mere satisfaction of curiosity.


    因为使用的是java,对其它语言只能供参考了,但是基本方法应该是类似的。

    美国这里有着很好的开源代码环境,最著名的是老牌的sourceforge,但是现在Google也提供了类似的服;还有很多大学都将自己研究的代码公布出来。很多时候利用或者学习别人的东西在进行开发,"站在巨人的肩膀上,逆向工程便是通向巨人肩膀的一条捷径。"【1】

    首先是下载源代码,一般都是直接下载zip的压缩包,也用使用SVN直接下载最新的开发包的。取决于你的要求了,是否要更上最新的开发进度。网站一般都会提供用户手册开发手册 ,这些文档尤其的重要,应当认真的阅读。有些时候网站还会提供一些FAQ,Wiki以及一些example或者Demo。

    在阅读代码前,一定要认真的阅读FAQ和get start,可以避免很多不必要的错误!

    阅读源代码需要一些基本知识,比如设计模式,XML,UML,JUnit等。现在的代码大部分都是社区模式,都应用了很多软件工程的模式。接下来导入代码到开发工具,我使用Eclipse为主,也会用NetBeans。很多时候导入都是很顺利的,如果源代码需要调用其它的类库,就需要设置jar路径,甚至自己去下载那些类库;如果涉及J2EE的,还要配置运行环境,这是题外话了。

    我基本上将源代码分为两种,带图形界面(GUI)的或者不带的。带GUI有一些特殊之处,后面单独再说。

    一般首先是看package,分析类之间的关系,这个时候UML很有用了。可以参考我之前的一篇文章【2】。接下来就是分析类里面的具体函数了,这个时候很需要分析以下函数调用关系,也叫做call hierarchy,这个一般是树形结构;如果采用图来表示,也叫做call graph。这里就具体说一些Eclipse里面如何进行函数调用关系的分析。

    这里有几个快捷键可以记住【3】:

    1. Ctrl+左键
    这个是大多数人经常用到的,用来查看变量、方法、类的定义
    2. Ctrl+O
    查看一个类的纲要,列出其方法和成员变量。提示 :再多按一次Ctrl+O ,可以列出该类继承的方法和变量。
    助记 :"O"--->"Outline"--->"纲要"
    3. Ctrl+T
    查看一个类的继承关系树,是自顶向下的,再多按一次Ctrl+T, 会换成自底向上的显示结构。
    提示 :选中一个方法名,按Ctrl+T,可以查看到有这个同名方法的父类、子类、接口。
    助记 :"T"------->"Tree"----->"层次树"
    4.Alt+左右方向键
    我们经常会遇到看代码时Ctrl+左键,层层跟踪,然后迷失在代码中的情况,这时只需要按"Alt+左方向键"就可以退回到上次阅读的位置,同理,按"Alt+右方向键"会前进到刚才退回的阅读位置,就像浏览器的前进和后退按钮一样。
    5.Ctrl+Alt+H
    如果你想知道一个类的方法到底被那些其他的类调用,那么请选中这个方法名,然后按"Ctrl+Alt+H",Eclipse就会显示出这个方法被哪些方法调用,最终产生一个调用关系树。

    5.Alt+Shift+Q, T

    这是用来显示,你可以将上面call hierarchy里面的任何一个函数或者拖到这个面板,它会分析类的调用关系,生成一个class hierarchy。

    有了宏观的UML再加上微观的函数调用关系,一般就能比较好的理解源代码了。

    还有一些其他软件(大部分我也没有用过),列在这里,或许有用:gprof, Ariadne,Slickedit,codeviz,DTrace。

    TIOBE 11月编程语言排行榜发布 C语言逼近榜首[from CSDN]

    【Csdn 11月12日编译】在TIOBE最近发布的11月编程语言排行榜上,最显著的变化是,排名第二的C语言和排名第一的Java语言差距更小,从榜单上我们看到两者只有大约1%的差距,而上次两种语言呈现出非常接近的市场份额是在2005年。事实上,Java和C语言都呈现长期下降的趋势,Java下降的趋势更加明显。

    两个月后,TIobo将宣布2009年年度编程语言,有机会获得这一奖项的是 C, C#, PHP 或者是 Objective-C。

    Objective-C增长明显,一年时间,它从第38名上升到了现在的13名,贴近前十。

    前20名排行榜:

    排行榜上前十名编程语言的长期趋势图如下:

    其他编程语言

    下面是排名21到50的编程语言。

    年度最热编程语言榜:

    Saturday, November 7, 2009

    C++和C#的性能比较

    场景是这样的,有个逻辑对象的结构如下:

    struct Msg
    {
      int type;
      char name[12];
      float height;
      float width;
      int count;
      int flag;

    }

    C++和C#分别来做这个对象的传输。

    传输方面没什么好说的,是操作系统IO的事情,和语言无关。

    下面是收到数据之后进行parse,为了对比,我们把数据parse一百万次。

    C++从socket收到char* input_raw_buf之后,只要:
    Msg* msg;
    memcpy(msg, input_raw_buf, sizeof(Msg));

    一百万次耗时20毫秒。

    C#从socket收到byte[] input_raw_buf之后,需要做:

    Convert.ToInt32()

    Convert.ToString()

    这种方式被批太落后,直接就没测试。

    C#优化,改用Marshal:

    一百万次耗时1781毫秒。比C++慢80多倍。据说和上面被批最原始的方式性能相当。有谣言说Marshal只是语法糖。

    C#再优化,改用BinaryReader:

    BinaryReader reader;

    msg.type = reader.ReadInt32();

    还不够快。

    再优化,改用伪指针的方式:

    fixed (byte* p = data)

    msg.type = *(int*)p;

    msg.name = new string((sbyte*)p, 4, 12)

    一百万次耗时484毫秒。比C++慢20多倍。

    无法可想,没法再优化了。

    最终的结果是,在parse二进制格式的数据的时候,C#比C++最少要慢20多倍。

    (建议各位,不要采用unsafe的方式构建C#程序)

    当然,我们也不会整天去parse二进制数据,因此C#众不用太担心。

    我也用C#写过不少程序,性能也都马马虎虎能接受。

    不过,一定要注意,C#在某些特定的环境下,有可能会慢得出乎你的意料。

    Friday, November 6, 2009

    GDB tutorial

    The original link of this article: http://www.cs.cmu.edu/~gilpin/tutorial/
     

    Debugging

    When to use a debugger

    Debugging is something that can't be avoided. Every programmer will at one point in their programming career have to debug a section of code. There are many ways to go about debugging, from printing out messages to the screen, using a debugger, or just thinking about what the program is doing and making an educated guess as to what the problem is.

    Before a bug can be fixed, the source of the bug must be located. For example, with segmentation faults, it is useful to know on which line of code the seg fault is occuring. Once the line of code in question has been found, it is useful to know about the values in that method, who called the method, and why (specifically) the error is occuring. Using a debugger makes finding all of this information very simple.

    Go ahead and make the program for this tutorial, and run the program. The program will print out some messages, and then it will print that it has received a segmentation fault signal, resulting in a program crash. Given the information on the screen at this point, it is near impossible to determine why the program crashed, much less how to fix the problem. We will now begin to debug this program.

    Loading a program

    So you now have an executable file (in this case main) and you want to debug it. First you must launch the debugger. The debugger is called gdb and you can tell it which file to debug at the shell prompt. So to debug main we want to type gdb main. Here is what it looks like when I run it:
    agg1@sukhoi agg1/.www-docs/tutorial> gdb main GNU gdb 4.18 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB.  Type "show warranty" for details. This GDB was configured as "sparc-sun-solaris2.7"... (gdb) 
    (Note: If you are using Emacs, you can run gdb from within Emacs by typing M-x gdb. Then Emacs will split into two windows, where the second window will show the source code with a cursor at the current instruction. I haven't actually used gdb this way, but I have been told by a very reliable source that this will work. :)

    gdb is now waitng for the user to type a command. We need to run the program so that the debugger can help us see what happens when the program crashes. Type run at the (gdb) prompt. Here is what happens when I run this command:

    (gdb) run Starting program: /home/cec/s/a/agg1/.www-docs/tutorial/main  Creating Node, 1 are in existence right now Creating Node, 2 are in existence right now Creating Node, 3 are in existence right now Creating Node, 4 are in existence right now The fully created list is: 4 3 2 1  Now removing elements: Creating Node, 5 are in existence right now Destroying Node, 4 are in existence right now 4 3 2 1   Program received signal SIGSEGV, Segmentation fault. Node<int>::next (this=0x0) at main.cc:28 28	  Node<T>* next () const { return next_; } (gdb) 
    The program crashed so lets see what kind of information we can gather.

    Inspecting crashes

    So already we can see the that the program was at line 28 of main.cc, that this points to 0, and we can see the line of code that was executed. But we also want to know who called this method and we would like to be able to examine values in the calling methods. So at the gdb prompt, we type backtrace which gives me the following output:
    (gdb) backtrace #0  Node<int>::next (this=0x0) at main.cc:28 #1  0x2a16c in LinkedList<int>::remove (this=0x40160,      item_to_remove=@0xffbef014) at main.cc:77 #2  0x1ad10 in main (argc=1, argv=0xffbef0a4) at main.cc:111 (gdb) 
    So in addition to what we knew about the current method and the local variables, we can now also see what methods called us and what their parameters were. For example, we can see that we were called by LinkedList<int>::remove () where the parameter item_to_remove is at address 0xffbef014. It may help us to understand our bug if we know the value of item_to_remove, so we want to see the value at the address of item_to_remove. This can be done using the x command using the address as a parameter. ("x" can be thought of as being short for "examine".) Here is what happens when I run the command:
    (gdb) x 0xffbef014 0xffbef014:	0x00000001 (gdb) 
    So the program is crashing while trying to run LinkedList<int>::remove with a parameter of 1. We have now narrowed the problem down to a specific function and a specific value for the parameter.

    Conditional breakpoints

    Now that we know where and when the segfault is occuring, we want to watch what the program is doing right before it crashes. One way to do this is to step through, one at a time, every statement of the program until we get to the point of execution where we want to see what is happening. This works, but sometimes you may want to just run to a particular section of code and stop execution at that point so you can examine data at that location.

    If you have ever used a debugger you are probably familiar with the concept of breakpoints. Basically, a breakpoint is a line in the source code where the debugger should break execution. In our example, we want to look at the code in LinkedList<int>::remove () so we would want to set a breakpoint at line 52 of main.cc. Since you may not know the exact line number, you can also tell the debugger which function to break in. Here is what we want to type for our example:

    (gdb) break LinkedList<int>::remove Breakpoint 1 at 0x29fa0: file main.cc, line 52. (gdb) 
    So now Breakpoint 1 is set at main.cc, line 52 as desired. (The reason the breakpoint gets a number is so we can refer to the breakpoint later, for example if we want to delete it.) So when the program is run, it will return control to the debugger everytime it reaches line 52. This may not be desirable if the method is called many times but only has problems with certain values that are passed. Conditional breakpoints can help us here. For our example, we know that the program crashes when LinkedList<int>::remove() is called with a value of 1. So we might want to tell the debugger to only break at line 52 if item_to_remove is equal to 1. This can be done by issuing the following command:
    (gdb) condition 1 item_to_remove==1 (gdb) 
    This basically says "Only break at Breakpoint 1 if the value of item_to_remove is 1." Now we can run the program and know that the debugger will only break here when the specified condition is true.

    Stepping

    Continuing with the example above, we have set a conditional breakpoint and now want to go through this method one line at a time and see if we can locate the source of the error. This is accomplished using the step command. gdb has the nice feature that when enter is pressed without typing a command, the last command is automatically used. That way we can step through by simply tapping the enter key after the first step has been entered. Here is what this looks like:
    (gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) y  Starting program: /home/cec/s/a/agg1/.www-docs/tutorial/main  Creating Node, 1 are in existence right now Creating Node, 2 are in existence right now Creating Node, 3 are in existence right now Creating Node, 4 are in existence right now The fully created list is: 4 3 2 1  Now removing elements: Creating Node, 5 are in existence right now Destroying Node, 4 are in existence right now 4 3 2 1   Breakpoint 1, LinkedList<int>::remove (this=0x40160,      item_to_remove=@0xffbef014) at main.cc:52 52	    Node<T> *marker = head_; (gdb) step 53	    Node<T> *temp = 0;  // temp points to one behind as we iterate (gdb)  55	    while (marker != 0) { (gdb)  56	      if (marker->value() == item_to_remove) { (gdb)  Node<int>::value (this=0x401b0) at main.cc:30 30	  const T& value () const { return value_; } (gdb)  LinkedList<int>::remove (this=0x40160, item_to_remove=@0xffbef014)     at main.cc:75 75	      marker = 0;  // reset the marker (gdb)  76	      temp = marker; (gdb)  77	      marker = marker->next(); (gdb)  Node<int>::next (this=0x0) at main.cc:28 28	  Node<T>* next () const { return next_; } (gdb)   Program received signal SIGSEGV, Segmentation fault. Node<int>::next (this=0x0) at main.cc:28 28	  Node<T>* next () const { return next_; } (gdb) 
    After typing run, gdb asks us if we want to restart the program, which we do. It then proceeds to run and breaks at the desired location in the program. Then we type step and proceed to hit enter to step through the program. Note that the debugger steps into functions that are called. If you don't want to do this, you can use next instead of step which otherwise has the same behavior.

    The error in the program is obvious. At line 75 marker is set to 0, but at line 77 a member of marker is accessed. Since the program can't access memory location 0, the seg fault occurs. In this example, nothing has to be done to marker and the error can be avoided by simply removing line 75 from main.cc.

    If you look at the output from running the program, you will see first of all that the program runs without crashing, but there is a memory leak somewhere in the program. (Hint: It is in the LinkedList<T>::remove() function. One of the cases for remove doesn't work properly.) It is left as an exercise to the reader to use the debugger in locating and fixing this bug. (I've always wanted to say that. ;)

    gdb can be exited by typing quit.

     

    Thursday, November 5, 2009

    TortoiseSVN使用方法

    转自:http://www.51testing.com/?uid-237750-action-viewspace-itemid-102424

    我们现在打开IE,在url处填入"svn://IP/project"输入用户名与密码我们就进入了版本控制界面,现在这里是空的我们手动创建几个版本文件夹出来

    我们在目录中可以看到project这个文件夹,点一下这个文件夹右键,选择Create folder填入自己想建的版本类的名字,使用这种方式建立不同类型的文件夹;既然是管理嘛我们就应该分门别类的建,不要所有的东西都放一起,这样就不便于管理了。

    我们现在已经建立了几个版本类了,下一步我们应该添加文件到这些类里,首先下载版本库到本地,找一个客户端,选择一个盘符右键选择SVN Checkout,在URL of repository中输入svn://IP/project;checkout directory中输入自己想要导出的盘符,其他默认选择ok;这样版本库就下出来了。然后选择一个版本类,把自己想要上传的文件拷贝进去,选择版本类文件夹右键选择TortoiseSVN->Add这样文件就被添加进去了,然后右键再选择这个文件夹选择SVN Commit,这样文件就上传到版本库了。

    到这里我解释下以上内容,从字面意思我们可以理解到,我们首先要创建版本类"creat folder"这里是创建一个文件夹,其次下载文件也就是说导出文件"check out",其次添加一个文件"add",上传也就是提交"commit"怎么样这样一说是不是清晰了些,虽然这些东西不是直接翻译过来的但是计算机语言这东西是要意通,这样你就很容易掌握很多英文版的软件;说了这些有人会问我文件添加了怎么去更新呢,下面我们接着说。

    更新客户端文件,选择目录文件夹右键选择SVN Update,把服务器版本库的文件更新到本第客户端去。

    把自己机器上的文件更新到服务器上去,直接commit。

    获取历史记录文件 show log。

    删除文件 delete。

    比较文件diff 好了这些常用的东西就这些,我不多说了,这些都是人家官方有的东西我也不必在这班门弄斧了。

    我在最后给大家介绍一个小工具ANKsvn这个工具是集成在VisualStudio中的一个插件,大家可以下载使用下,如果找不到地址可以向我要,我的联系方式就不说了自己在我日志中找吧,其使用方式与客户端差不多不过使用起来很方便,不过要在SVN客户端安装了才可以用。

    公司绝不会告诉你的20大秘密

    感觉说的有些方面很适合 graduate students, 其实现在和导师的关系跟公司的雇佣关系没有什么区别,今天supervisor说:"You should do them both, one is your class project and the other one is your GRA *JOB*." 可以说她一句话点醒了我,job这个词用的可以说是恰如其分......闲话不说了,上货,大家共享这些宝贵的知识。
     
    1.入职时的工资高低不重要,只要你努力工作你会得到相应待遇的

      我估计几乎找过工作的人都听过这句话,当我们确定被聘用跟公司谈工资时,他们都会说"如果以后你业绩突出、努力工作,你的报酬也会相应增加的",特别是当第一次找工作的时候大多数人会相信这些话,但是千万~~别相信。
      刚入职时,你的工资就是你的全部(当然有一些岗位,比如销售或弹性工资的岗位除外),而且你入职以后大部分待遇都会跟着你的工资而浮动,工资调整也是按你目前的工资乘于一定的百分比,保险、公积金也跟工资有关系,当你的基本工资低的时候你今后的报酬增长空间也不大。
      所以,找工作时千万不要心软,多争取一些基本工资,因为这是你的所有。
      我第一次找工作时就是犯了这个错误,当时心软没要求更高的工资,当时觉得基本工资比别人低几百块钱无所谓,但是后来才发现它有一个杠杆作用,尽管以后每年你工资涨幅比别人大,但是工资还是比别人低。
      比如你入职时的基本工资为4000,第二年涨幅为20% (一般的企业极少数人能涨20%),那第二年工资为4800; 如果你的同事入职时基本工资为4500,第二年涨幅为10%(一般涨幅),那他第二年工资为4950。
      是不是看到差距了? 请记住,入职时工资就是你的全部,一定不能心软。

    2.人事部不是你的倾谈对象

      我在公司看过很多员工找人事部经理谈话,而且人事部员工可能会定期找员工谈话,问员工在工作中有没有遇到什么问题? 有没有人事部需要帮员工解决的事情?
      但是请你记住, 公司人事部并不是你的倾谈对象,人事部的首要任务不是去帮助雇员,而是保护公司利益不受雇员损害,这才是最为重要的。可能很多人认为人事部门是自己的朋友,有时甚至连对公司、对老板的真实态度都会告知于人事部门。(如果你经常这样的话,我可以肯定的说,你会跌得很惨,而且不会有人告知你原因的)
      无论人事部的人员表现得何等友好,你均要认清,你跟他们的谈话内容,他们必然会与决策部门分享这些信息,例如你的老板、经理、主管及首席执行官。人事部门的职责就是(有时也是合法的)告知公司决策部门你那些所谓的" 秘密"。
      比如你不喜欢你目前的工作内容、或与老板的关系处理的不好,你千万不能找人事部抱怨,你应该直接跟你的老板沟通。可能当时谈话时人事部的员工会给予同情,说自己向自己的上司反映这个情况,但是大多数情况下人事部门会将你与他们的对话原封不动地转达给你的老板,而你的老板对此是绝对无法原谅的,出现问题首先不去找老板解决,而是直接找到人事部门,这样你的处境就很被动了,有可能被迫离开公司了。

    3.你的能力并不能确保你的安全

      很多公司在招聘员工或对外宣传时说我们公司注重员工的能力,提倡员工能发挥自己的主观能动性(确实有一些公司是提倡创新的,但是极少数,大部分都只是打打口号而已)。对于刚入职的员工来说可能都会有一种心理,那就是向同事或领导展示你的才华、展示你的能力,但是请注意:公司或你的领导倒希望先看到你的忠诚,而不是显摆自己的能力。不管你的目的是什么,这个并不重要,如果你一贯展示你的能力,很有可能上司觉得你卖弄小聪明、是一个不值得信赖的人,或他会感受到威胁,如果他认为你在威胁他的位置,他才不管你有多聪明,他宁愿要一个愚笨但对自己忠诚的人。
      所以,当你刚入职或刚调到一个新部门的时候,千万不能先自作聪明,你首先要做的是熟悉环境熟悉上司同事的性格,即使你是一个专家也要先摆低姿态,当然必要的是关键时刻也需要显示自己的能力,让别人觉得你是深藏不露。
      韩国有一个俗语说"要想让婚姻生活幸福,就要当3年聋子,3年哑巴,3年盲人" ,因为以前在韩国婆婆对媳妇很是虐待,你必须是装聋作哑才能熬过去(当然现在已经不是这种情况了),我说这个的目的是新来乍到,你应该学会作哑装聋,刚开始多听、多学,听到闲言碎语要装聋。

    4.报销单是公司测试你的一个工具

      看到这个题目或许你会纳闷?报销单也能测试员工?是的,我们平时不以为常的报销单也是公司或领导测试你的一个工具。
      大部分公司都会有月底报销(餐费、交通费、电话费等)或出差报销吧?
      你让你的领导在你的报销单上签字的时候,他有没有说过什么?或他有没有做过什么表情? 请注意,其实大部分情况下领导们都会看你报销的金额,而且如果他们愿意的话财务部门可以随时提供每个人的报销明细。
      以前看过一些在公司里面贪小便宜的人,餐费、交通费里总是放着一些自己私人用的(而不是为了公司业务)费用,或许这些费用只有100元,但正是这些小钱会坏了你的前程。
      我认识的一个老板跟我说过这样一句话:"某某员工哪天报了业务餐费,但是那天明明是我付款了。"或许这位员工太大意了。
      但是我认识的老板当中也有一些人,他连你打的票上面的时间也核对,然后把属下每个员工的每月费用都记录下来,或许你报销的时候他可能不会说什么,但是到时候你丢掉的并不仅仅是金钱。

    5.在工作场合中透露私事很危险
      现在我们大部分人有太多时间跟同事一起过,我们跟同事在一起的时间有时甚至超过跟家人在一起的时间,这种情况使我们有时分不清公事和私事,有时候觉得跟同事的关系像亲人一样,跟同事分享自己的私事,孩子养育问题,个人健康问题,经济上遇到的一些困难等,但是请记住,职场就是职场,你这样做很危险。
      我的一位同事经常在工作场合说他儿子现在是青春期,跟我们描述怎么怎么叛逆,由于儿子的叛逆,每天回家以后家里的氛围都很紧张,有可能他是想通过倾述减少来自家庭的压力,但是最近公司开始了一个重大的项目,他一直以为自己是最佳候选人负责这个项目,但是结果令人意外,公司领导层选了其他人选,为什么呢?因为公司领导层觉得"他家里的事情已经够多了,估计他没有余力做这么重要的项目"或讲得更冷静一点就是"你连自己家里的事情都解决不了,你还能负责这么重要的项目吗?"
      如果你自己身体不太好,不需要把自己的健康情况告诉同事或上司,因为对上司来说你不健康说明你不能百分之百投入或有可能影响工作,这样你的上司会不安,他甚至会提前想对策或再额外招人,这样的话到时候即使你的身体恢复了,你有可能会面临失去自己位置的尴尬局面。

    6.如果你与老板作对,必然会被逐出公司大门 

      在公司里有一个对你产生很大影响的人,如果没有他的支持你不能得到公司的认可,晋升也很难甚至有可能丢掉你的工作,他就是你的顶头上司。
      或许你的上司没有你聪明、没有你能干,你或许对他并不服气,但是请记住,他就像是一个守门人一样,你想绕开守门人,但最终的结果是你也失去了给你敞开的一扇机会门。或许你觉得如果你自己足够有能力,公司领导层会让你绕开你的上司直接让你晋升或给你另外的机会,但是不要做白日梦了,公司往往会站在你上司的角度想一个组织的稳定性,跟自己的上司斗99%受伤的都是你自己。
      或许你的上司能力没有你强,但是既然他能上升到那个位置就说明他必然有一些其他方面的能力,领导力或组织管理能力或对公司的忠诚,当上司和你产生冲突时公司会站在你上司这一边,请你记住这一点。
      我的一个同事很有能力,当他调到一个新部门的时候发现上司根本没有能力而且往往做不了决定,所以很多情况下他绕开自己的上司直接跟总经理沟通,而且在业务上总经理也认可了他,这让他很得意以为自己能力强上司不能拿他怎么样,但是有一次,上司说他工作太辛苦了,让他去马尔代夫休假(公司出钱),当他从马尔代夫回来以后发现,他不在的时候公司发了一个人事调令,把他调到一个无关紧要的部门。
      所以,不管碰到什么样的上司,如果你还想呆在这个部门,呆在这个公司,你需要配合你的上司,这样他会帮你打开一扇机会的门。

    7.按了发送键? STOP~~ 公司邮件很危险

      如果我说你用公司邮箱收发的邮件都被你的上司所看到,你是不是觉得天要塌下来了?如果不是的话,那就说明你很光明正大。其实很多人都不知道公司或上司能看到你的邮件,而且公司也绝不会给员工发个警告,说要注意互相往来的E-mail,如果你用公司邮箱给朋友发私人邮件,或跟同事用邮件谈论上司或公司的政策,一定要睁大眼睛看一下:公司邮箱很危险。
      
      (1)你利用公司邮箱收发邮件时,你一定要想着有可能公司某人正在看这封邮件,因为真的有些公司会定期检查一下邮件内容(当然是不告知于员工的情况下),我不知道之前我任职的公司是不是也这样,但是我听过一些国际知名公司会定期查员工的邮件。
      (2) 邮件会永远留在公司服务器: 你或许不知道,就算有些邮件发完了你后悔了马上删除了,可能在你的邮箱里面是已经没有了,公司服务器永远记录这封邮件的。
      (3)按发送键的时候一定要三思:你或许通过邮件给人事部或你的上司提一些建议或者对公司制度做一些评论,一定要注意,这些邮件在一些重要时刻会成为呈堂证供,很多情况下往往对你不利。
      
      在公司里面我经常收到一些群发的搞笑邮件,如果以前你给同事群发过这些邮件,我建议你以后不要再发了。因为你经常发这些会让别人觉得你整天没事做,所以才发这种邮件。或许收到这些邮件的他(或她)把这个邮件转发给一些领导了,或许他也是为了让领导搞笑、高兴,但是领导们可不会这么想,你在领导的眼里会变成整天无所事事的人的。

    8.我努力工作公司会给我加薪?No,你必须要求!

      对于工资,公司和员工之间永远都不能达到双赢,很多人对自己目前的工资并不满意。那么怎么办呢? 等着公司给你加薪?很多人认为如果我做好自己的事情,我出业绩了,公司肯定会给我加薪,是的,公司会给你加薪,但是~~ 加薪的幅度肯定不能满足你的期望。
      我在公司里看过很多案例,很多人都幻想"到时候"公司会给我加薪,或害怕自己提要求以后老板有什么想法所以不敢提出来,但是如果你不敢提出加薪,公司给你的可能就是一个平均值或略高于平均值的薪水,它不是你所期待的。
      
      当然你想要求加薪,首先你要弄清楚你的"价值",而且必须是站在公司的角度想,如果公司认为你没有"加薪的价值"还提出要求,那你很有可能会被裁掉的。
      (1)证明你的"价值":如果你在公司整天无所事事,那公司肯定不会给你加薪的,在要求之前你必须要证明你的"价值",让你成为公司不可缺少的人才。
      (2)提要求:像前面所说的一样,公司每天都想着怎么削减成本,如果你不要求公司觉得这是一件好事情,除非你要求了,公司绝不会自愿给你涨很多工资的。不要想着哪天会出现奇迹,如果你觉得你有价值,就要求吧,如果上司认可你,他会倾听你的话语的,并且千万不能让你老板成为你的敌人,交流的最后一定要强调我还是尊重你的决定,因为有些时候由于客观的原因老板也有身不由己的时候。
      (3)不要威胁上司:如果你还想待在公司,在要求加薪时,千万不要威胁上司,比如不加薪就离开公司或跟上司说谎说已经拿了别的公司的OFFER等,你的立场必须是"我很喜欢这个公司还有目前的业务,但是我觉得目前的工资跟我实际做的工作有差距,我希望工资能体现我的价值"等,你威胁的结果很有可能是得打包走人。
      (4)不要抱怨:即使最后的结果不是很好,比如不给你加薪或加了很少一部分,通过主动出击你可能明白了自己的短处或老板对你的看法,也让老板明白了你不满足于现状。如果你没有打算离开这个公司,你就要现在开始弥补自己的短处或提高自己的业绩,下次再用更强烈的事实来证明,可能这次没有成功,但是你离下次成功就不远了 。
      我知道跟老板提加薪要求很难,因为你害怕"如果我要求提工资,老板会炒我或以后他对我不给好脸色怎么办呢?",但是大多数情况下那些你想像的最坏的情况并没有发生,大多数是happy ending。而且即使有一些副作用,公司或老板很健忘的,因为如果这个公司的OWNER不是你上司的话,钱不是从他口袋里出来,过一两个月他就会忘掉这件事情的。
      这个我可以很肯定的告诉你,因为我曾试过。

    9. 加薪必须要求,那晋升呢? NO,千万要管好自己的嘴巴~~

      既然说加薪必须要求,那晋升呢?这个千万不能要求,一旦你申请或要求晋升机会,它就会与你失之交臂,晋升不是要求的,而是上司通过认真考虑之后给予你的。
      上司还没有确信你能不能成为管理人员之前你先要求,这就像是你不从大门进,而是要跳过墙进到内部。因为如果上司还没有确信你是一个当领导的料,但你先提出来,他会觉得你还没有成熟或认为你比起公司的利益更在意自己的私利。
      领导们在决定晋升人选时除了业绩、工作能力之外,还会考察很多其他能力,比如领导能力,组织能力,对公司的忠诚度等,而且作为管理人员应该要沉得住气、该谦虚的时候需要谦虚,你事先提出来会破坏你的形象的。
      难道要坐等吗?当然不是,你可以主动负责一些重要的项目、要提出帮助其他部门面临的棘手的项目等,一定要抓住机会让上司看到你的能力,看到你的热情。
      
    10.如果遇到新上司要积极配合他 

      现在的公司经常会发生人事变动,一般来说遇到新上司属下的员工都会有一点被别人侵入的感觉,特别是当你和前任上司关系非常好的时候这种感觉更强烈。但是如果你想在公司继续混下去,你要尽快配合新上司,熟悉他的工作作风。
      很多时候新上司赴任以后下属员工都期望新来的上司适应部门原来的工作方式,但是这种事情不会发生的,大部分新上司都会对目前的工作方式进行变更,这种时候千万不要带头抵触或提意见,所谓新官上任三把火,这时候你要做的是积极配合他,如果别的员工有不满情绪,你应该要中间周旋一下,这样新上司会觉得你是站在他这一边的,这个第一印象特别重要。同时,新上司刚来时,你觉得新上司还不懂部门的情况,所以就出面给他一些忠告或建议,就算你是为了新上司好,千万不要提忠告或建议,这是一个禁忌。如果他主动问你,你可以说,但是~~这种时候也尽量说事实,不要涉及到你个人的意见或负面的信息,你要让你的上司根据这些事实自己做出决定。况且新上司问你的意见或建议,是想测试你们的忠诚,想知道你们对公司或同事的真实想法,这很有可能是一个圈套。
      在这里你要记住一点的是,新上司来了熟悉业务的时候对你来说是一个很好的表现自己的机会,记住,少说,默默配合新上司的工作,他会把这些都会记在心里的。

    11. 想成为公司中最有价值的员工?那你就必须停止说"我做不了"而主动请缨

            是不是人人都想成为公司的MVP? 那你必须要停止说"我做不了"而主动请缨,每次上司给你分配任务的时候你是不是说 "我没做过这个,我做不了这个"或"我现在没时间这个"。
      就算是你觉得这个任务对你来说有点难,你觉得你有可能完成不了, 这种时候很多人可能条件反射地说"这个我做不来", 千万不要这样说. 其实领导给你分配这个任务, 他肯定是考虑过你的能力,而且可能这件事情即使没做好他也有后路的. (一般领导不会给你安排很重要而且如果搞砸了没有后路的事情) 这种时候即使你完成的不够好可能也不会损失什么, 这种时候你的态度应该是"这个我做起来有些难, 但是我会试试的" . 然后就得通宵加班或使上你全身力气把问题给解决. 如果你做的过程中发现按你现在的能力完成不了, 你一定要在deadline之前提交给领导(不要在最后一天提交完成度不高的答案, 领导最讨厌这种人),让他有更多时间来修改。
      
      如果你习惯性的说"我做不了",过一段时间以后他会觉得"给你任务你肯定说做不了",所以干脆不给你指派任务.
      
      如果你们部门里有所有人都不想做的项目或任务,如果你主动请缨接收这个"烫山芋",那领导会对你刮目相看,给予你很好的评价的,当然这种烫山芋不需要太多,只要一个就可以.
      
    12. 想要脱颖而出?让领导感到150%满足感

      在职场成功的一个秘诀, 不要只干领导让你做的事情,。如果你只是按照领导说的话100% 执行, 那你永远也无法脱颖而出。在公司做领导给你分配的任务的时候,一定要多长一个心眼, 除了他布置的任务以外, 你可以提出你的建议或者是一些改善意见, 而且完成度不能是100%, 而是要达到150%.
      
      "做女人要像希拉里一样"中希拉里用的战略中一个很重要的战略就是: " 让雇佣我的人或者是接受我提供的服务的人感到200%的满足感", 这样看希拉里的目标更高.
      
      很多人都觉得你只要做好领导分配的任务让你的领导满足100%, 做好自己分内的事情就可以了,但是如果这样做, 你在职场永远不能混好.
     
    13. 你们公司允许言论自由吗?职场没有言论自由

      或许当你第一天上班的时候人事部的人会对你我们公司很OPEN,而且在很多时候开会的时候总经理会说"大家畅所欲言吧,我会尽力满足你们的要求、尽量解决你们所提的意见",千万不要陷进这个陷阱。大多数时候公司是没有言论自由的,特别是当你对公司的政策,环境或制度说出了真实的想法,在公开场合上反对公司的政策制度,公司会视你为影响公司氛围的反动派,他们觉得你很危险所以通过一些方法让你打包走人的。
      我不知道有些真的开放的公司是不是有言论自由,但是我看到的版本是每当总经理跟员工面谈时都会让他们畅所欲言,但是等他们真正说出了真实想法,马上他就失去了公司的信任。
      还有一点,我经常看到一些人在电梯里跟同事或朋友说公司里面的事情,这个是一个很不专业的行为,因为不管你是在你办公室的电梯还是在客户公司电梯,跟你一起乘坐电梯的人有可能是你上司的朋友,重要的客户,你称赞公司可以,但是反对或不满的话语千万不要在电梯里面说,不然到时候你都不知道自己为什么死得这么快了。

    14. 你的办公桌专业化吗?

      现在大部分外企的办公桌都是一格一格的小格子,或许你认为办公桌是我私人的地方,我想放什么就放什么,但是请注意,办公桌也是体现你价值的地方,所以要让你的办公桌也变得专业化。
      那怎么样的办公桌才是专业化的呢?

    (1)不能太乱,我在公司里看到很多人的办公桌都是乱七八糟的,各种各样的文件摆在那里,太乱的话很容易给别人这个人工作没有条理的印象。
    (2)不能太整洁,如果你办公桌上什么都没有太整洁了,那别人会觉得你根本没事做。
    (3)不能有太多装饰品。现在80后追求个性,办公桌上面放着各种各样的东西,曾经我的同事中有一个人的办公桌可以看作是一个礼品店,各种各样的娃娃还有各种小东西,可能自己觉得这样很有创意,但是别人都在背后说她。
    (4)跟业务无关或跟你的调不符的书籍千万不要放在让人看到的地方。
      
      总的来说,我觉得白天你可以把你的文件或资料放在桌上,但是下班的时候一定要整理,那些重要的资料一定要放在抽屉里(最好是锁着),这样可以显示出你做事很专业。而且现实生活中有些上司习惯下班以后转一圈看看下属的办公桌,一是看看你的桌上有没有公司重要的资料敞开着,二是通过你办公桌上的东西看看你最近的动向(如果你桌上有"8个方法教你找好工作"之类的书,那你应该是有跳槽的打算了吧?^^)
      
    15.业绩考核结果跟你的业绩不相符?业绩也需要进行宣传

      大部分公司每年都会进行1到2次(或4次)的业绩考核,业绩考核结果会影响到你的奖金/晋升等,但是很多员工发现业绩考核结果跟自己想象的完全不一样,这是为什么呢?因为业绩考核中你主观性的判断根本不重要,重要的是你的上司怎么判断你的业绩。如果你做的工作是拿数据说话的,像销售等,可能还好一点,但是我们很多人做的工作可能没有具体的数据来支持,这种时候你平时也要对自己的业绩进行宣传了。
      我看过很多人平时都不怎么跟上司沟通,但是一到年底对考核结果不满,就找上司透漏不满,这种做法无法改变什么,你需要做的是
      (1)要跟上司做定期的沟通:跟自己的顶头上司定期沟通是很重要,因为通过这种沟通你可以让上司知道你正在做的工作,同时你也可以了解上司到底想什么,对你期待什么。按自己的标准来做事在公司里是站不住脚的,如果想要获得好的绩效评价,你必须要满足上司的期待和标准。
      (2)对自己的业绩进行宣传:大家肯定会问这个怎么宣传啊?上司不都在看着吗?但是很多时候你做的一些事情上司还真不知道,不管你多么努力工作,如果上司不知道的话就没用,所以必要的时候一定要把一些工作进展的情况CC给上司,或我一般是采取定期把自己正在做的工作列个目录,详细描述进行情况发给上司,上司在进行绩效考核的时候可以参照这些书面的东西。
      (3)即使上司给了你一个不好的评价,你不能透漏不满。因为上司这样做肯定是有他的理由的,而且他有权力给你不好的评价。你需要做的是让上司说出来他的意见,你要根据上司的意见来进行改正,因为你有义务迎合上司的工作方式、工作作风,谁让他是你的上司呢?

    16. 你是不是公司里的"好好人"?如果一味地讨好他人,你便会失去他人的尊重


      每个公司都会有好好人,他们对于所有人都笑眯眯,对于所有人的要求都不会说"NO"。如果你是新进入公司的员工,可能刚开始要得到其他同事的信任,需要讨好别人,当然这个是需要的,但是请你不要搞混"谦虚、摆正态度"和 "没有自己主见的好好人" 。如果你一味地讨好他人没有一点自己的主见,你会失去他人对你的尊重,在工作中别人也会把你看作是没有真学问的空瓶。
      
      我知道这个说起来简单做起来难,有些时候是需要讨好人,但是面对重要的事情或重要的业务时,如果你认为你的想法是正确的,你应该坚持,不能一味同意别人的观点,要有自己的主见。
      
      以前听朋友说他们公司有一个人,对于任何人拜托他的事情他都说好,结果到后来公司里的所有杂事都摊到他那里去了,他自己是为了这些琐事而整天忙碌,但是别人在后面则会笑话他。当时听的时候我想,他的同事们怎么这样啊?但是一想,估计这些事情都是他咎由自取的。对于不合适的工作或拜托,或对工作的正确的意见,如果你认为正确的话,你都应该要提出来,不能做个"好好人",这两者的度怎么掌握,那还是看个人所处的环境或性格了。^^
      
    17.不要隐藏自己的失误

      我们在工作中难免会犯一些失误,所有人都有一种心理,那就是想在别人不知道的情况下隐藏自己的失误。但是有一点请注意,如果你所犯的失误涉及到你们部门或你的上司,你一定不能隐藏,因为很多时候隐藏自己的失误带来的是更大的失误,正所谓越遮越丑,就算你犯的是一个很低级的错误,你也要告知部门负责人或相关人员。
      
      我刚开始工作的时候犯了这个错误,刚开始写企划案的时候修改的次数会比较多,因为上司和我之间来来回回的版本比较多,所以最后把最终版本发给上司以后自己发现有一些数字错了,因为是刚开始负责企划案,不想让别人知道我的疏忽,我就偷偷改了这些数字,因为第二天上司跟老总开会时我会把资料打印出来给他们。第二天当我把打印出来的资料递给上司,上司瞅了几眼,正好看到了那些数字,他就大发雷霆。他发火不是因为我出现了失误,因为每个人都难免会失误,问题是我想偷偷隐藏这个失误,并没有考虑上司的立场。如果当时他没发现这个,到时候给老总报告时发现了,老总正好也对这个数据有印象(因为资料是提前发给老总的),而他自己不能自圆其说的话会有什么样的后果。
      
      这件事情对我的启示很大。我并不是说所有的失误都要公开,如果这个事情不涉及到别人,你自己一个人就解决的话你就不用公开。但是如果这个失误会波及到你的上司或组织,一定要提前告知他们,并想办法解决。所有人都会失误,如果你非常负责地处理你所犯的失误,它不会让你难堪,反而会给你加分的,因为领导们觉得你很诚实而且有责任心。但是请注意,事情过去以后同样的错误你不能再犯一次。

    18.休了病假或产假吗?你需要注意了

      病假和产假是一个很好的福利制度,最近发现公司里怀孕的人比较多,大多数人认为法定的"病假或产假"是严格受法律保护的权利,但是你一定要注意,这有可能会把你陷入两难境地。当然,当你休长期病假(法定的)或产假还有哺乳期间公司是不能解雇你,但是如果这段期间你处理不好的话,一旦过了这个时期你就会上"黑名单"上。因为公司的员工数基本上是固定的,一旦你休几个月的假,这段期间你的工作会分到别人的头上或公司要额外的招人,过了几个月以后当你回来很可能已经没有你的位置或让你做的工作了。
      那么怎么样才能防止这种情况呢?
      (1)假期期间,持续跟公司的联系,特别是跟你上司的联系:我知道对于刚生孩子休产假的人来说这个应该很难,因为有太多事情让你操心,但是我还是希望你能定期抽时间跟上司或同事联系,聊一下工作的事情,或有重要的项目时如果可以的话你也可以给一些建议,但是这些,必须要让你的上司。
      (2)一定要与时俱进,不能丢"业务感觉"。我们学外语的时候语感很重要,但是一旦你放了很久,你就没有语感了,这样你整个外语水平就会下降。工作也是一样的,你必须对你的业务保持那种"业务感觉",如果可以的话在家里也看一下相关资料(当然是在你的身体允许的情况下),因为你一旦上班,公司或上司会有一段时间"观察"你,看你的工作能力或效率是不是跟以前一样。
      
      我朋友的一个同事就是刚生完孩子上班之后状态特别不好,其实这个是情有可原的,因为小孩晚上闹精神状态就不太好,肯定会影响白天上班。但是公司不能接受她不能集中精力工作,休完产假以后过了1个月后,上司就慢慢不给她工作,而且把她手头上的工作也慢慢分给别人,最后是那个同事自己受不了无所事事就提出辞职了,这个可能就是公司所愿意的。如果她没有主动提出辞职,估计过了哺乳期以后公司也会用各种理由裁她的。
      
    19. 劳动法并不能保护你

      可能很多人会觉得现在随着法律的完善,特别是随着劳动合同法的修订等,劳动法会保护我们,但是不要对劳动法抱有幻想,它并不能保护我们。因为正所谓"上有政策下有对策",公司的人事部或外部的人事机构会巧妙的绕过法律,保护公司的利益。

      举一个例子,从新劳动合同法第39条中明确规定劳动者有下列情形之一的,用人单位可以解除劳动合同,如"严重违反用人单位的规章制度的",用人单位的规章制度很多样化,我们公司以前制定一个"公司员工手册"时,我们看到光是工作纪律这块就列了100多条^^ 几乎你所想到的或没想到的都列了出来,到时候如果公司真的要辞掉你,很简单,在这么多条当中肯定适用于你的。
      
      而且一般公司想裁你会通过一些措施来让你"主动辞职",比如上司经常给你分配你无法完成的任务,或上司对你的态度很冷淡让你无法忍受,你的办公桌移到非常不好的位置,给你一个很短的期限完成一个根本不可能完成的任务,给你很低的评价等,如果有这种征兆的话,你应该好好考虑自己的职业规划并做打算才行。

    20.赢才是硬道理

      说了这么多,或许给一些即将进入社会或刚进入社会的师弟师妹们一种恐惧的心理,想着公司怎么都这样啊。或许这个不是适用于所有的公司,因为我也碰到过好的公司,好的上司。
      
      但是不怕一万就怕万一,我希望大家都提前准备能保护自己的武器,可以绕过这些陷阱。如果你有才能,你必须要充分发挥出来并让别人知道,并让他们给你打开一扇机会之门。
      
      我们的人生就像是一场赌博,职场更是一场赌博,你可以选择你出的牌,从而决定自己的输赢。
      
      在职场无望的等待天上掉馅饼不是明智之举,你应该积极地占据主动位置,学会"赌博",学会扭转局势,因为赢才是硬道理。

    开发人员一定要加入收藏夹的网站<转载>

    开发人员一定要加入收藏夹的网站

    http://www.gotapi.com/
     语言:英语
     简介:HTML,CSS,XPATH,XSL,JAVASCRIPT等API的查询网站。
    http://www.w3schools.com/
     语言:英语
     简介:W3C制定的标准诸如XML,HTML,XSL等等的在线学习教程。
    http://www.xml.org.cn/
     语言:中文
     简介:可以说是XML的中国官方网吧。W3C标准的翻译组织与XML系列技术交流社区.
    http://www.connectionstrings.com/
     语言:英语
     简介:这里几乎收集了所有的数据库连接字符(connectionstring)了。
    http://www.itpub.net/
     语言:中文
     简介:我个人认为是国内最专业的综合性行业性技术类社区.
    http://www.netvtm.com/
     语言:中文
     简介:内容多翻译于w3schools.com,少有原创。不过还是应该鼓励精品翻译。
    http://www.regexlib.com
     语言:英语
     简介:正则表达式库。搜索正则表达式用。
    http://www.rexv.org/
     语言:英语
     简介:用Ajax开发的在线正则表达式验证器.
    http://www.koders.com/
     语言:英语
     简介:代码搜索引擎,可以搜索几十种语言的代码。
    http://www.123aspx.com/Rotor/
     语言:英语
     简介:.Net Frameworks的源代码。
    http://dotnet.aspx.cc/
     语言:中文
     简介:孟宪会的资料站,虽资料大多比较简单,却解决了开发中的大部分问题?!
    http://www.dofactory.com/Patterns/Patterns.aspx
     语言:英语
     简介:23种设计模式的实现参考。特点是UML+精练的示例代码+简洁的解说风格。
    http://www.open-open.com/
     语言:中文
     简介:Java开源大全,如果你用.NET,照着它的名字前加N找找应该都有吧 ?!:)
    http://www.riacn.com/
     语言:中文
     简介:我认为是国内少有的RIA专业技术站于交流社区.
    http://www.cnpaf.net/
     语言:中文
     简介:中国协议分析网,很全面的协议资料网。
    http://www.pinvoke.net/
     语言:英语
     简介:通过.net调用win32等非受控API的资料大全。
    http://bbs.51js.com/
     语言:中文
     简介:无忧脚本,专业的脚本技术社区。
    http://www.c-sharpcorner.com/
     语言:英语
     简介:C# Corner,学习c#的好地方.
    http://blog.csdn.net/group/experts/
     语言:中文
     简介:CSDN专家群,汇集CSDN专家的电子报.
    http://www.codeproject.com/
     语言:英语
     简介:有很多可学习的示例代码,特点是丰富,深入浅出.
    http://www.gotdotnet.com/
     语言:英语
     简介:微软开发维护的关于.net framework交流社区.
    http://www.sourceforge.net/
     语言:英语
     简介:全球最大的开源软体站点
    http://www.asp.net/QuickStart/
     语言:英语
     简介:Microsoft .NET Framework SDK QuickStart Tutorials
    http://www.matrix.org.cn/
     语言:中文
     简介:与 Java 共舞,Java优秀的专业社区,文章质量很高.做.Net的朋友也可以从其借鉴很多知识.

    万物通一理——谈计算机专业学习(转自杨中科的笔记)

    原文请看:杨中科的笔记
     
    今天和一位朋友(微软的一位资深架构师,按照年龄、阅历分,我叫他老师)吃饭,聊到他的爱好,他喜欢国学和习武,聊到国学的时候,他就说现在他在做一个网站,就是传播真正的国学,而不是像易中天那样披着学术的名义说评书。我问他搞这种真正的国学会不会不像易中天那样"大话国学"那么流行、那么赚钱,他说 "我只是想传播一种正确的思想,相信大家都会有能力辨别正确的思想,当大家知道那些人是在恶搞国学而我是在真正的弘扬国学的时候,人的趋向争取东西的本性就会使得他接受我的正确的东西,而且会把这种正确的东西传播给其他人"。想一想这和我在如鹏网的工作也是有相似点的,现在主流的宣传口号都是"大学里学的东西过时了,没用了",因为这是符合宣传这种想法的人们的利益的,而我在传播的"大学里学的东西永远不过时,只是需要同学们多动手"也是"非主流"的,但是是我认为正确的,这种正确的思想也在使越来越多的同学"趋向争取东西的本性就会使得他接受我的正确的东西",而且有很多同学都是靠"正确的东西传播给其他人"的这种方式知道我的这些想法的。

    又谈到哲学的问题,说到很多人学哲学的时候都是死记硬背那些哲学的原理,背了半天什么真正的东西都没学到;而有的人则是看了古今中外的很多史料、案例,悟出一些道理,然后再来看那些哲学的原理,发现这些哲学原理都很容易的和之前学的史料对应上,这样轻松的就从本质上掌握了这些哲学的原理。我又联想到同学们学计算机,很多人把编程语言当成理论学,背关键字、背函数、背代码片段,到头来什么都没学到,而有的人则一边学一边练程序,练过大量程序以后再来看书指导自己的实践,反正掌握的更牢靠。

    接着又谈到了关于武术的问题。他说在练武术的时候很多人都去学那些套路、招式,最后学到的只是花拳绣腿,真正的武术大家是不看重那些招式的,他们那些招式都是在实战中悟出来的,没有定法,灵活运用,两次不同的实战中用到的都是不同的招式。而那些招式只是给想"学学玩"、"学一学到别人面前显摆"的人用的,让他们学上两招去唬人,是一个玩具而已,其实什么用都没有,要想学到真正的武术必须下苦功自己练,多实战,然后自己悟。和学计算机一样,很多人学黑客,其实就是拿一些真正的黑客开发出来的黑客工具"玩一玩",满足一下虚荣心而已;有的人学编程则学一大堆MFC、Struts之类的框架、工具,到处炫耀自己"懂得高级编程技术",到最后却连最基本的一个for循环都写不好。

    最后还谈到了学哲学中的"只和一个师傅学",他的一个朋友去学哲学,问师傅世界上这么多哲学的书什么时候能看完,师傅告诉他只看一本书就可以,他用了五年的时间看这一本书,然后五年后师傅把其他的哲学书拿到他面前,他翻了翻就说"师傅我明白了,这么多不同的书其实本质上都是说的一样的道理,不用看其他的书了"。我又联想到同学们学计算机,有的同学刚学C++的时候就惊呼"听人说有好多C++的经典书《Essential C++》、《Thinking in C++》 、《C++ Primer》 、《Exceptional C++》、《More Effective C++"》……是不是要都学完才是掌握了C++,这要学到身边么时候呀?",我和他说"你把你现在学的C++的教材学好了,每个程序都能熟练的写出来,然后再回头看这么多不同的书其实都不值得看了",事实也是如此,经过半年多的苦练,等他回来再翻这些书他说了一句话"这些当年我想像的大部头现在翻起来都大同小异,每本书能挑出5页对我有价值的东西都很难"。

    万物通一理!

    A very interesting and helpful article, which tries to teach you how to implement a interpreter by yourself!

     
     There are 5 continuous articles by now. Each section describe a specified topic and detail of implementing such a interpreter.

    Tuesday, November 3, 2009

    Some my understanding of the research on Linux and Windows

    1. the difference of usability between operating system
        As Linux is under GNU license, everyone can distribute him or her own Linux version. So the hole Linux industry and academic community are separated. This situation looks like the conflicts between Democracy and Capitalism. Democracy provides more freedom to people, but Capitalism has higher efficiency. For example, Microsoft provides a total solution for software distribution, including compiler, packaging and managing tools. In the other side, Redhat/Fedora Linux use "yum" and "rpm" as their default software installing and managing format, but Ubuntu and Debian Linux use "apt" and "dib" to do the same thing. Furthermore, those two groups of users do not want to merge to a unique format on Linux, as they are all too confident on their own techniques to accept the others`. This problem also can be seen in user-interface design. KDE, GENOME and xface are all try to keep some characteristics and attract/keep their users. By doing this, the isolation even increase. 
        The result of such community isolation is that it is impossible to provide an universal easy-to-use system as there are so many specification and modification you need to make. For hardware and software providers, updating and maintain their products on all distributions would be very expensive. Furthermore, as the softwares, even the operating system itself, are developed by a huge number of companies, communities and individuals, so it is impossible to keep all of them in one style. For example, Mplayer may have a dependency on mmx.so.6, but Xine may depend  on MMX.so.5. If the user do not have the capability to read error information and install them properly, it is very likely that the user cannot use the software they want and finally give up to use.

    2. the documentations of WPF/D3D and G3D/OpenGL
        As WPF, D3D, Blend are all products and Microsoft wants to sell them to the developers, so Microsoft hire a lot of programmers, scientists and engineers to enrich the documentation and code examples. We can search the definition of every function and class of WPF from MSDN.com. In addition, it is easier to get source code and examples, as there are a lot of developers, may be hired by the company, maintain blogs, which show a lot of code segments to help new user to start up. This is also true for Matlab. However, as most packages we used on Linux are opensource or free, the developers do not have enough strength to maintain a documentation as good as those companies. For example, when I use G3D to draw characters on the screen, the documentation, which is supposed to be 500 pages, provides no information about how to use Gfout. The next thing I do is sending help request to the developer`s forms. They answered my question nearly 20hours later. During that time, I solve the problem by reading the source code. 

    3. tools on Linux and Windows
        This topic is very familiar with the topics we talk above. On Windows, Microsoft provides a very long, unified, optimized product line. 


    4. The power of Linux

    5. ......