生活在Linux中

昨天被一个小问题折腾了很久很久,决定把它记下来。

原本用的好好的Debian GNU/Linux 5 (Lenny),在经历了以下操作后出现了问题:更新了一下系统;安装配置了NetworkManager;把内核从2.6.31.5升级到2.6.31.6(同时把内核选项中的CPU类型由686改成CORE2); 把ATI显卡驱动从9.10升级到9.11。出现的问题是:重启或注销GNOME时系统失去响应;Firefox在链接上点右键,菜单弹出前软件失去响应。

为了排除这两个问题,做了很多的努力:Google寻找解决方案;把内核恢复到老版本;把CPU类型恢复成686重新编译内核;降级显卡驱动;重新配置Xorg.conf;以上几种方案的各种组合……均无果而终。(重点怀疑显卡驱动的原因是ATI的fglrx驱动在新内核中总是会触发一些oops)

山穷水尽之际,决定用strace看看Firefox在弹出菜单时到底在做什么事,为什么会卡住。

connect(88, {sa_family=AF_INET, sin_port=htons(16001),
sin_addr=inet_addr("127.0.0.1")}, 16...

127.0.0.1……我自己ping了一下这个本机回环地址,Request timed out。啊……

原来,这次安装了NetworkManager后发现它不工作,查了一下才知道只要是在/etc/network/interfaces中有配置的网卡都不会被NetworkManager管理,于是不管三七二十一把interfaces这个配置文件给清空了。遗憾的是原本在interfaces配置文件中配置的Loop Back网卡lo不会被NetworkManger管理的,于是127.0.0.1这个地址就不通了。

这个故事也告诉我们,lo网卡在Linux中非常重要。

1999年第一次安装Linux,2006年参加工作开始试图把Linux作为日常的操作系统,到目前为止,却还是没有办法完全离开Windows。不过对于Linux的看法早就已经从欣喜的发现“Linux也能做这件事”演变成了“遗憾,Linux还做不了这件事”,或者,更确切的说“遗憾,Linux还不能兼容这个东西”。毕竟,外面的世界还不是这么美好。Linux自身做为桌面系统来说,也还有不少的路要走。

昨天Google开会正式介绍了深度整合Linux和浏览器的操作系统Chrome OS,大概在一年多前在参加UCDChina书友会时,大家就曾经聊到过浏览器是不是可能变成操作系统,在来看来,这个理想已经更接近现实了。第一时间下载了Chrome OS镜像在VMware上体验。不过实话说,现在所看到的Chrome OS并没有给人特别惊喜,几乎纯粹Web OS的概念很领先,但就目前来看似乎并不具备足够的吸引力,毕竟现在Web还没有能力提供足够丰富和复杂的应用。更不提那众所周之原因所导致的Chrome OS的桌面无法打开,一些应用无法正常访问了。

跑题了……

Fedora也在谋杀你的硬盘?

10月底看到注意!Ubuntu的Bug可能会减少笔记本硬盘寿命这篇新闻(原始相关讨论在这里),没有往心里去。但昨天看到Fedora的论坛上也在讨论这个问题,说Fedora也存在相同的问题,于是开始警觉起来。

问题不是很复杂,就是使用命令:

sudo smartctl -a /dev/sda | grep Load_Cycle_Count

重复执行这个命令看一下硬盘SMART功能中记录的Load/Unload次数,在Ubuntu或Fedora等Linux下,我们会发现这个 值很快的增长,而一块硬盘可以承受的Load/Unload次数是比较有限的。我的Seagate ST980815A硬盘可以承受的次数是600000,而我现在从smartctl中读到的数字是115000,并且以一分钟2次左右的速度增长。这样算 来,硬盘虽然不会立即就会结束它的寿命,但也算是折寿得够快的了。

实际的情况,比这里描述的还要复杂一点,比如:在使用AC电源和电池的时候,行为不一定一样;不同厂家的SMART中记录的 Load_Cycle_Count值的含义可能并不一样;为什么这个问题在Windows下不出现?是硬盘firmware还是主板BIOS还是操作系统 的问题呢?

可以参考的资料不少:

http://ubuntuforums.org/showpost.php?p=3675960&postcount=26

https://bugs.launchpad.net/ubuntu/+source/acpi-support/+bug/59695

https://www.redhat.com/archives/fedora-devel-list/2007-October/msg02260.html

http://fedoraproject.org/wiki/FWN/Issue107#head-10d9e6175a2dbef23ed071339345ccc747588683

看到头脑发涨,其实这个问题还是没有结论,倒底对硬盘的影响有多大也还是不得而知,但总结一下,最保守可行的做法就是修改硬盘的节电参数,尽量减少它做不必要的Load/Unload动作。方法是执行下面的命令:

sudo hdparm -B 254 /dev/sda

这个命令把硬盘高级电源管理的参数改成254(默认一般是128),这样就可以大大减少硬盘做Load/Unload的动作。这样做的副作用是在使用电池供电时硬盘也不能及时的进入节电状态。

通过写ACPI消息的响应脚本,可以让这个命令在系统开机、待机唤醒、休眠唤醒时都得到执行,可惜偶还没研究出来怎么在Fedora上写,还好 我很少用待机和休眠,所以就直接把hdparm -B 254 /dev/sda这命令写在/etc/profile中的最后一行吧。现在开机以后硬盘的Load_Cycle_Count已经基本上不发生变化了。

libeasycgi

经过两个工作日的审核,终于成功在SourceForge上创建了一个项目,名为libeasycgi(SF Project页面http://sourceforge.net/projects/libeasycgi)。

这个项目试图实现一个方便用C++进行Web CGI程序开发的一个库,主要的目标是:

  • 借鉴ASP的一些模式(主要指ASP中那几个对象)使C++开发CGI程序可以有一个比较方便、确定、易维护的模式。
  • 提供一些常用的机制,如输入合法性检查、HTML Injection Attack保护等,使CGI开发出程序有一个基本安全保证。
  • 提供一种机制让CGI程序具有更好的可测性,使自动化测试的可能性可以提高。

创建这个项目前在SourceForge上搜了一下相关的项目,很多,但试了一下,基本上都不好用。除此之外,没有做更多的Research,所以可能这个项目又是有点在“造轮子”了。而且用的还是CGI和ASP这样的“过时”技术,不过没关系,醉翁之意不在酒,自己开这个项目的主要目的是:

  • 自己实践一个完整项目设计、开发、发布过程
  • 尝试熟悉一些开源系统和软件的使用,包括:Emacs, Subversion, autoconf, CppUnit, doxygen, rpm, gcc, apache, php, mysql
  • 尝试实践:跨平台程序的开发,G11N,XP & TDD。

Scope还是挺大的,一步步来~一开始先只在Linux上做,也不用autoconf,打算先实现一个很简单Prototype,然后依据从Prototype中得到的经验,进行一下设计,然后再一步步完善。

今天创建了项目,发现SourceForge果然还是很强大的提供一整套完整的服务:Tracker, CVS, SVN, Web (with PHP, CGI and MySql), SSH, Mailling List, File Release System等等,而且除了规定这些设施只能用于项目开发以外,其它的限制并不多,比花钱租一个虚拟服务器可强多了。

如何在C++中动态分配二维数组-续

回头看一下前一篇《如何在C++中动态分配二维数组》才发现它是挂羊头卖狗肉,文中只提了从ChinaUnix上拿来的那个C的实现,还是没有结论说对于C++的对象应该怎么处理。今天抽空写了一下。

关键点还是在于placement new和显示的析构函数调用,用于保证对象可以正常的构造和析构。

不过这个实现也还是有不少缺点的,比如,数组的大小必须记住,才能保证析构所有对象。不过这点可以通过改进分配方法算法,把数组大小也用一点空间保存起来。

另一个缺点是,从语法上看,很容易让人误把darray_new返回的指针以为是数据区的起始地址,从而可能导致一些逻辑错误。

其实正像ftofficer在前一篇文章的留言中说的那样,最好的办法还是不要“造轮子”了,有强大的Boost放在那里不用实在是太浪费了……

#include <iostream>
#include <cstdlib>
#include <new>
template <typename T>
T **darray_new(int row, int col)
{
int size = sizeof(T);
void **arr = (void **) malloc(sizeof(void *) * row + size * row * col);
if (arr != NULL)
{
unsigned char * head;
head = (unsigned char *) arr + sizeof(void *) * row;
for (int i = 0; i < row; ++i)
{
arr[i] = head + size * i * col;
for (int j = 0; j < col; ++j)
new (head + size * (i * col + j)) T;
}
}
return (T**) arr;
}
template <typename T>
void darray_free(T **arr, int row, int col)
{
for (int i = 0; i < row; ++i)
for (int j = 0; j < col; ++j)
arr[i][j].~T();
if (arr != NULL)
free((void **)arr);
}

如何在C++中动态分配二维数组

这个问题应该是我在CSDN蹭分时回答次数比较多的一个问题了,我的回答一般是三种方法:(1)用vector的vector,(2)先分配一个指针数组,然后让里面每一个指针再指向一个数组,这个做法的好处是访问数组元素时比较直观,可以用a[x][y]这样的写法,缺点是它相当于C#中的一个锯齿数组,内存空间不连续。(3)直接分配一个x*y大小的一维数组,这样保证空间是连续的,但访问数组元素不直观。对于我这个“经典”回答,我那时还一直是挺得意的,至少从蹭分的角度来看,这样回答还是很有效的。

今天在ChinaUnix论坛闲逛时看到一个贴子,再次证明了我在C++方面才疏学浅。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void **darray_new(int row, int col, int size)
{
void **arr;
arr = (void **) malloc(sizeof(void *) * row + size * row * col);
if (arr != NULL)
{
void *head;
head = (void *) arr + sizeof(void *) * row;
memset(arr, 0, sizeof(void *) * row + size * row * col);
while (row--)
arr[row] = head + size * row * col;
}
return arr;
}
void darray_free(void **arr)
{
if (arr != NULL)
free(arr);
}

嗯,连续分配内存,而且可以用a[x][y]的方式来访问!可谓二维数组动态分配的绝妙方法!这段程序是C的,似乎要改成支持对象分配的C++版也不是什么难事(不过估计得用上placement new吧,嗯,需要再思考一下……)。