提高效率——使用awk代替shell读文件

2012年5月2日 没有评论 20 次访问

对一个号码文件进行操作,调用的处理事件越来越慢。

曲线如下

脚本大致如下:

#!/bin/bash

while read seq

do

echo $seq

done < seq.dat 阅读全文…

分类: shell 标签:

一天一句话

2012年2月20日 没有评论 22 次访问

2012-02-20

打印流水log是发现并恢复问题的最好方法之一。

2012-02-21

gcc以__i386__来 进行32位编码,而以__x86_64__来进行64位编码。

2012-02-22

明确需求再开发,先联调接口再进行各自开发才最优效率,初期想得多,后面少走弯路。

2012-02-23

竖排垂直标签就会吸引到顾客的注意——《超市长得一样一定有道理》

2012-03-06

问题:svn: Can’t convert string from ’UTF-8′ to native encoding

解决方法:export LANG=”en_US.UTF-8″

2012-03-07

pragma   pack(push,1)   ==   pragma   pack(1)

pragma   pack(pop)    和      pragma   pack() 作用是一样的

2012-03-14

vim 十六进制显示
:%!xxd
正常显示
:%!xxd -r

2012-05-16

cat /proc/sys/fs/file-max

查看最多打开文件数量

分类: 每日一句 标签:

删除svn目录

2012年2月16日 没有评论 16 次访问

当向svn添加目录时,如果目录下有.svn目录,会出现冲突。

所以在引用代码时总是先删除掉.svn目录,使用以下命令。

find . -name ".svn" -exec rm -rf {} \;

find . -name ".svn" | xargs rm -rf

具体的含义可以参考《find命令总结》

find命令将所有匹配到的文件一起传递给exec执行,有些系统对能够传递给exec的命令长度有限制,这样在find命令运行几分钟之后,就会出现溢出错误。

注意:在删除文件前最好先打印一下查找到的文件,核对下是否是要删除的。

分类: 脚本操作 标签:

makefile小技巧

2012年2月16日 没有评论 16 次访问

1.操作打文件makefile要加上宏


-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE

2.如果要make时打印警告信息,又不输出有符号和无符号比较、变量定义未使用警告


-Wall -Wno-sign-compare -Wno-unused-variable
分类: makefile 标签:

如何在pm和de之间生存

2011年12月4日 没有评论 13 次访问

  在小项目中,通常人力不足时会让开发担任pm职务。一般情况下,担任pm的时候是不用编码参与开发的,但是也有特殊的时候,这时就会有既当教练,又当运动员的情况发生。
  
  其实原本这也没什么,但是经历后才发现,不容易,如果再给一次机会,还是会有很多提高的空间。
  
  如果想要做到游刃有余,那么必须去分好自己的角色,知道什么时候我是pm,什么时候我是de。即使在一个会议上,也要想清楚,我这段时间是从pm回答,这段时间是从de的角度阐述。有些左右互搏的意思,如果搞不定,也有个简单的办法,只扮演pm,de让另一个搭档来。 阅读全文…

分类: 博客相关 标签: , ,

如何提高会议效率

2011年11月20日 没有评论 12 次访问

  平时工作中,交流的方式很多,邮件、im、电话、会议。其中会议是最有效、直接的沟通方式,但是也存在着耗时成本高的问题。所以当会议来临,如何提高会议效率,是一件值得仔细考虑的事。
  
  一、要请和会议内容有关系的人
  
  可能看着是句废话,但是确实有需要我们注意的地方。一个项目,可能汇集了多方,但是我们的会议议题可能只是开发方案的问题,那么就不要把数据分析、运维的人都叫上。浪费的时间比较多,会让无关的同事受到影响,另外人数多了也增加了组织者的压力。
  
  二、要有主持人和决策人
  
  一般会议组织者作为主持人,或者会议的受益者。总之要有个人来主持会议,把握会议的发展和流程。这点很重要,主持人要知道会议的背景和议题,交代完背景后引导大家讨论。
  
  会议也要有决策人,否则无法确定最后结论,一定要有说得算的人在场。
  
  三、要确定会议需解决的问题
  
  会议开始时就要确定要解决的问题,越细越好,根据问题的具体情况决定会议流程。会议有明确的目的,不至于中间跑题,根据问题的解决多少来判断一次会议是否成功。
  
  四、把握会议流程和时间
  
  主持人要根据会议的解决问题来引导流程,当有人发散和跑提时,即使把议题引导回来。如果问题解决不了,根据时间判断,尽早去讨论下一个问题,不要在节外生枝的问题上花费太多时间。例如是过进度的会议,那么直接讨论上一期做了什么,下期准备做什么,有什么问题,最后讨论问题解决方法。尽量把能交代的问题交代后再发散。另外会议时间不要太长,人会疲劳,效果也不好。一个小时左右为宜。
  
  五、输出会议纪要
  
  会议结束后要及时输出会议纪要,把会议解决问题列出,写出会议解决方法。相关人都要收到或抄送到,另外也要把解决问题需要的人和时间明确写到纪要中,作为对后面工作的一个衡量方法。
  
  六、跟进结论
  
  会议只是商定方法,后面执行的效果,还是要跟进的。
  
  做到以上几点可以说会议的效率就很高了,会议的目的也达到了,但是说着简单,实现起来很难,还需要实践中多摸索。

关于编译器链接静态库的一些特性

2011年11月18日 没有评论 17 次访问
有这样一个工程目录:

-test/

-dir1/

libtest.a

test.cpp

test.h

test.o

-dir2/

libtest.a

test.cpp

test.h

test.o

main.cpp

Makefile

 

其中,dir1test.cpptest.h中定义了func_afunc_b

#include <iostream>

using namespace std;

 

#include “test.h”

 

void func_a(void)

{

cout << “a” << endl;

}

 

void func_b(void)

{

cout << “b” << endl;

}

#pragma once

 

void func_a(void);

void func_b(void);

 

dir2test.cpptest.h中只定义了func_a

#include <iostream>

using namespace std;

 

#include “test.h”

 

void func_a(void)

{

cout << “a” << endl;

}

#pragma once

 

void func_a(void);

 

main.cpp调用了func_afunc_b

#include <iostream>

using namespace std;

 

#include “test.h”

 

int main(void)

{

func_a();

func_b();

 

return 0;

}

 

我们列出下面几种方式编译mainMakefile和编译结果如下:

#dir1的静态库在前,dir2的静态库在后ok

main1: main.cpp

g++ -g -Wall -I./dir1 -I./dir2 -o $@ $^ -L./dir1 -ltest -L./dir2
-ltest

 

#dir2的静态库在前,dir1的静态库在后fail

main2: main.cpp

g++ -g -Wall -I./dir1 -I./dir2 -o $@ $^ -L./dir2 -ltest -L./dir1
-ltest

#编译结果:main.cpp:9: undefined
reference to
`func_b()’

 

#dir1.o在前,dir2.o在后fail

main3: main.cpp

g++ -g -Wall -I./dir1 -I./dir2 -o $@ $^ ./dir1/test.o ./dir2/test.o

#编译结果:dir2/test.cpp:6: multiple
definition
of `func_a()’

 

#dir2.o在前,dir1.o在后fail

main4: main.cpp

g++ -g -Wall -I./dir1 -I./dir2 -o $@ $^ ./dir2/test.o ./dir1/test.o

#编译结果:dir1/test.cpp:6: multiple
definition
of `func_a()’

 

#dir2.o在前,dir1的静态库在后fail

main5: main.cpp

g++ -g -Wall -I./dir1 -I./dir2 -o $@ $^ ./dir2/test.o -L./dir1
-ltest

#编译结果:dir1/test.cpp:6: multiple
definition
of `func_a()’

 

#dir1.o在前,dir2的静态库在后ok

main6: main.cpp

g++ -g -Wall -I./dir1 -I./dir2 -o $@ $^ ./dir1/test.o -L./dir2
-ltest

 

clean:

rm -f main[0-9]

 

原因好像是这样的:

编译器链接多个.o时,没有顺序的概念。

但是链接.a时,为了节省工作量,

1)只链接需要用到的(摘抄一段说明:“传统的Unix编译环境下,静态库的加载是顺序搜索一遍,遇到没链接的函数就记下,如果这个函数在后面的库或obj中出现,链接器就会把这个函数所在的obj链接过去,,不包含未链接函数的obj就会被忽略过去(静态库也只是obj的简单打包而已)。于是, -lc”的时候, 因为那两个函数在main.c中都没有被调用,链接器就把a.o略过去了,“-ld”的时候虽然有了a.o中函数的调用,但链接器已经把它给略过去, 找不到了。);

2)相同名字的.o只用第一次出现的。

分类: 开发知识 标签:

linux下动态库基础及C++下使用的注意事项

2011年11月18日 没有评论 59 次访问
 【图】

 

【生成动态库】

lib0x513pb.so: plugin_0x513.cpp oidb_0x513._0x513.pb.cc

        ${CC} ${GPB_INC} $^ -fPIC -shared -o $@ ${GPB_LIB}

 

【注册动态库路径】

添加动态库所在path/etc/ld.so.conf

运行/sbin/ldconfig令配置生效。

 

【使用动态库】

tdb_now_demo: tdb_now_demo.cpp

${CC} ${GPB_INC} -rdynamic -o $@ $^ ${GPB_LIB} -L. -l0x513pb

——直接链接。修改动态库后,需要重启tdb_now_demo加载动态库,程序不会自动加载。

 

tdb_now_demo: tdb_now_demo.cpp

${CC} ${GPB_INC} -rdynamic -o $@ $^ ${GPB_LIB} -ldl

——配合dlopen()等函数。修改动态库后,程序可以自动检测并加载,不需要重启。

 

dlopen的使用】

 Dl API

函数

描述

dlopen

使对象文件可被程序访问

dlsym

获取执行了 dlopen 函数的对象文件中的符号的地址

dlerror

返回上一次出现错误的字符串错误

dlclose

关闭目标文件

该过程首先是调用 dlopen,提供要访问的文件对象和模式。调用 dlopen 的结果是稍候要使用的对象的句柄。mode 参数通知动态链接器何时执行再定位。有两个可能的值。第一个是 RTLD_NOW,它表明动态链接器将会在调用 dlopen 时完成所有必要的再定位。第二个可选的模式是 RTLD_LAZY,它只在需要时执行再定位。这是通过在内部使用动态链接器重定向所有尚未再定位的请求来完成的。这样,动态链接器就能够在请求时知晓何时发生了新的引用,而且再定位可以正常进行。后面的调用无需重复再定位过程。

还可以选择另外两种模式,它们可以按位 OR 到 mode 参数中。RTLD_LOCAL 表明其他任何对象都无法使加载的共享对象的符号用于再定位过程。如果这正是您想要的的话(例如,为了让共享的对象能够调用原始进程映像中的符号),那就使用 RTLD_GLOBAL 吧。

dlopen 函数还会自动解析共享库中的依赖项。这样,如果您打开了一个依赖于其他共享库的对象,它就会自动加载它们。函数返回一个句柄,该句柄用于后续的 API 调用。dlopen 的原型为:

#include <dlfcn.h>
void *dlopen( const char *file, int mode );

有了 ELF 对象的句柄,就可以通过调用 dlsym 来识别这个对象内的符号的地址了。该函数采用一个符号名称,如对象内的一个函数的名称。返回值为对象符号的解析地址:

void *dlsym( void *restrict handle, const char *restrict name );

如果调用该 API 时发生了错误,可以使用 dlerror 函数返回一个表示此错误的人类可读的字符串。该函数没有参数,它会在发生前面的错误时返回一个字符串,在没有错误发生时返回 NULL:

char *dlerror();

最后,如果无需再调用共享对象的话,应用程序可以调用 dlclose 来通知操作系统不再需要句柄和对象引用了。它完全是按引用来计数的,所以同一个共享对象的多个用户相互间不会发生冲突(只要还有一个用户在使用它,它就会待在内存中)。任何通过已关闭的对象的 dlsym 解析的符号都将不再可用。

char *dlclose( void *handle );

void invoke_method( char *lib, char *method, float argument )
{
void *dl_handle;
float (*func)(float);
char *error;

/* Open the shared object */
dl_handle = dlopen( lib, RTLD_LAZY );
if (!dl_handle) {
printf( “!!! %s\n”, dlerror() );
return;
}

/* Resolve the symbol (method) from the object */
func = dlsym( dl_handle, method );
error = dlerror();
if (error != NULL) {
printf( “!!! %s\n”, error );
return;
}

/* Call the resolved method and print the result */
printf(” %f\n”, (*func)(argument) );

/* Close the object */
dlclose( dl_handle );

return;
}

int main( int argc, char *argv[] )
{
char line[MAX_STRING+1];
char lib[MAX_STRING+1];
char method[MAX_STRING+1];
float argument;

while (1) {

printf(“> “);

line[0]=0;
fgets( line, MAX_STRING, stdin);

if (!strncmp(line, “bye”, 3)) break;

sscanf( line, “%s %s %f”, lib, method, &argument);

invoke_method( lib, method, argument );

}

}

c++使用动态库的注意事项】

动态库的头文件.h中需要使用

#ifdef __cplusplus

extern “C”{

#endif

 

……

 

#ifdef __cplusplus

}

#endif

 

void *dlsym( void *restrict handle, const char *restrict name );

C++有Name Mangling机制。用g++编译的库文件,自然的运用了Name Mangling技术,原本的getdate(DateType& d)函数,很有可能其名字已变成了_getdate_DateType(DateType& d)(以支持多态,不同的编译器实现不一样)dlsym发现查找不到指定的函数名,运行的时候就会报错。

分类: 开发知识 标签:

估算(from猪和鸡)

2011年11月18日 没有评论 18 次访问

 

72法则

假设以年利率r%投资一笔钱y年,如果ry=72,那么你的投资差不多会翻倍。

——72法则用于估算指数过程的增长非常便利。

Little定律

系统中物体的平均数量等于物体离开系统的平均速率和每个物体在系统中停留的平均时间的乘积。

常用数据

今天花一点小时间来做一些小实验,记住一些常用的数据是值得的,因为它们能帮助我们在将来做出明智的决策,从而节省更多的时间。

放大系数

我建议为了补偿我们的知识局限,在估算实时软件系统性能时,以246的系数来降低对性能的估计。

Roebling被问到他设计的大桥是否会如其他许多大桥一样垮掉时,他说:不会,因为我按照所需强度的6倍设计了这座大桥,可以防止那种情况的发生。

分类: 博客相关 标签:

函数调用的堆栈

2011年11月18日 没有评论 25 次访问
  

1321440763_94.png

 

1321440772_19.png

 

1321440780_29.png

 

首先我们来看一下显示调用栈所依据的原理。每个线程都有一个栈结构,用来记录函数的调用过程,这个栈是由高地址向低地址增长的,即栈底的地址比栈顶的地址大。ESP寄存器的值是栈顶的地址,通过增加或减小ESP的值可以缩减或扩大栈的大小。现在我们再来详细地看看这个过程:

①在栈上压入参数。

②执行CALL指令,在栈上压入函数的返回地址。

③压入EBP寄存器的值。(上一层函数的栈帧“<每个函数在栈上都会保存有一个EBP值,标志了一个函数调用的开始,这就像分界线一样,将每个函数调用区分开来>压栈)

将ESP寄存器的值赋给EBP寄存器。(本函数的开始地址<ESP是当前栈顶的位置>赋值给EBP,在这个函数结束之前,EBP都存储着这个函数的开始地址)

⑤减小ESP寄存器的值,为局部变量分配空间。

⑥执行函数代码。

将EBP寄存器的值赋给ESP寄存器,等于回收了局部变量的空间。

⑧弹出栈顶的值,赋给EBP,即将第③步中压入的值重新赋给EBP。

⑨执行RET指令,弹出栈顶的返回地址。如果被调用函数负责回收参数的空间,则需要增加ESP的值。

  

函数调用过程的第③步和第④步使得各个压入的EBP值形成了一个链表的结构,而EBP寄存器是链表的表头,如下图所示:

1321440793_97.png

正是这种链表结构的存在,使得获取函数调用栈成为可能。只要从EBP寄存器开始,沿着链表层层往上,就可以得到函数调用的轨迹。

 

由于EBP在当前函数调用中的不变性,调试版的程序都使用EBP作为变量和参数的基址,将EBP的值与一个偏移值相加就可以得到变量或参数的地址。有些发行版的程序会对函数的调用过程进行优化,省略了压入EBP的步骤,因此不能再使用EBP作为变量和参数的基址,也不能使用EBP链表来获取函数调用栈。


(这篇不是原创,是贴了3篇文章的一部分,自己也写了几句话。一边查找信息一边粘贴,引用的文章已经找不到了——态度很不严谨,以后注意~~)

分类: 开发运营 标签:

Switch to our mobile site