2008年10月30日星期四

Linux&UNIX 程序开发基础教程 笔记1

这本书只要讲一些Linux上一些基础命令和工具,内容很简单。这里的笔记主要是记录一些看着不怎么熟悉的内容。最近打算来个什么“大干XX天,Linux上道“,万一失业了,艺也多了个。

Linux笔记

只记录自己看着不大熟悉的东西

man -k passwd 列出所有可能是查找项

cp -p (-p为保留权限和修改时间)

find /usr/include -name socket.h -print -exec file '{}' \;
;表示有参数, {}为find的结果,\是;的转义符.{}必须放入''中

whereis vs which
whereis强大点,还可以显示man page

grep -n(显示行号) "asdfasd" *.txt

标准输入
catgrep "john"
标准输出
cat>Phones
[your input]
Ctrl+D

标准错误输出
ls -l foo 2> error.log
将标准输出和标准错误输出定向到同一个文件
ls -l foo 2> error.log 1>&2, 如果一个符号依赖于另一个符号,就必须依照从左到右的顺序指定重定向。
>>代表追加

命令1|&命令2
将命令1的标准输出和标准错误输出和命令2的标准输入相连

命令1|tee 文件列表|命令2
cat text.cxx text.cxx~|grep "main"|tee file1 file2|wc -l

chmod可以修改的权限位一共有4个3bit,SUID,SGID,粘滞位

SUID位
SUID位的文件被执行时,该文件将以所有者的身份运行,也就是说无论谁来执行这个文件,他都有文件所有者的特权。如果所有者是root的话,那么执行人就有超级用户的特权了。这时该位将变成一个安全漏洞,因此不要轻易设置方位 。
SUID位显示有s和S之分,如果用户本来没有执行权限,用chmod u+s 文件,设置SUID位,用ls -l显示的话是S,如果事先已有了执行权限,显示为s.

SGID与上相同,不过是组ID,命令为chmod g+s 文件.

粘滞位
要求操作系统在可执行程序退出后,仍在内存中保留该程序的映象。这样做是为了节省大型程序的启动时间,不过会占用系统资源。 命令为chmod +t 文件

用&加在命令最后,将命令放入后台
find / -name foo -print>foo.paths 2>/dev/null&

ps a 终端上所有的进程
ps -e 所有进程
ps aux 详细信息
ps auf|more 详细信息,包括进程关系

fg/bg %进程号
把进程转移到前台/后台

kill -l 列出所有信号编号

Ctrl+Z将程序挂起

tar归档解档
tar -zcf gc.tar.gz ./yfgc/
tar -zxf gc.tar.gz

记录一个bug

最近改的一个bug比较麻烦.症状是一个.NET程序调用我们写的Native code出错,死锁了.用WinDbg观察,发现是死在.NET层中用于垃圾收集的一个线程中,叫Finalize thread,专门用于收集不用的unmanaged的资源.下面这篇文章具体描述Finalize thread的死锁.

http://dotnetdebug.net/2005/06/22/blocked-finalizer-thread/

我对.NET完全是白痴,只用C#写过几个demo程序用来验证API,看着这情形就晕了.不过还是可以看到,一个生存在STA套间的线程(大概是主线程),在等Finalize thread完成,而Finalize thread则在等待一个STA的COM组件的反应.于是死锁发生了.

现在在回忆的时候,觉得这一切再明显不过.不过在调查这个bug过程中,却觉得非常困难,原因有2,首先是不懂.NET,看着这些就有障碍.再者,这个项目是在已有代码的基础上继续开发,对原有的代码不熟悉,还有些程序根本就没有源代码,比如调用我们Native code的.NET程序.

问题在于在使用那个COM组件前后,调用了CoInitialize(NULL)和CoUninitialize(),实际这个是不必要的,因为在每个线程起来时都会调用,这里其实只是重复调用,当时没有多想,只是为了保险写了这样两句.而调用这段的Native Code的线程则是在MTA中的,问题就这样出现了.也有文章说这个事情的.

http://blogs.msdn.com/benkuhn/archive/2006/09/15/756401.aspx

大概是说CoInitialize和CoUninitialize的nest call,如果是进入不同的模式,会引起COM库的引用计数混乱.去掉这一对对CoInitialize/CoUninitialize,程序正常.

非常想研究下.NET的内部架构,这样的错误就不会犯了.

2008年10月9日星期四

C++语言的一个违反直觉之处

6.2章,才发现这样一个陷井。
如下一段代码在gcc4.2下是可以触发Segmentation fault的,原因在于基类与派生类的大小不同。
#include

using namespace std;

class Point{
public:
Point(){
}
virtual ~Point();
};

Point::~Point(){
cout << "~Point" <
}

class PointImp:public Point{
int _x;
int _y;
public:
PointImp(){
cout << "PointImp" <
}
virtual ~PointImp();
};

PointImp::~PointImp(){
cout<< "~PointImp" <
}

int main(){
Point* p = new PointImp[10];
delete[] p;
return 0;
}

如果把PointImp中的成员int _x, int y移除,程序就好了。Lippman书上解释了一些内部实现的原因,不过我觉得还是可以使语言支持这样的操作更好,毕竟符合人的直觉。