Archive for June, 2007

Typical Chinese Programmer

Friday, June 1st, 2007

FatMouse 在 Java 课上介绍了 Typical Chinese Programmer 的概念。我不知道这个名词从何而来,在 Google 上似乎也没有找到有用的信息。不过 FatMouse 说 Typical Chinese Programmer 是这样的一类人,他们想当然地写程序:

  • 比如,他们做出来的界面上有一堆按钮,他们假定用户会先点击“按钮一”,再点击“按钮二”然后是“按钮三”。如果用户不按照这个顺序点击,那么程序就会莫名其妙地 Crash 掉。然而他们也并没有给任何提示给用户以说明点击顺序,或者是在第一个按钮点击之前禁用掉第二、第三个按钮,因为他们认为用户一定不会笨到不按照他们心里想的顺序去点击按钮的。
  • 再比如,他们打开文件从来不判断文件是否打开成功。“怎么会打开失败呢?”他们这样想。他们觉得,每次都检查是否打开成功实在是太麻烦,打开失败的概率实在太小了,要真的打开失败了,就到时候再加上判断语句吧。

于是,他们写出来的程序里面充满了不确定因素。

我最近两天都在调试一个 C++ 程序,后来发现有一次错误就是由于队友犯了 Typical Chinese Programmer 式的错误造成的。

程序是由 Qt 搭建而成的。最开始发现了一个极其棘手的 Bug ,我在我的 Linux 极其上根本无法重现这个 Bug ,但是在队友的 Windows 机器上则很容易重现,要命的是,如果启动调试模式,则很难碰到问题,如果是直接运行,则必定出问题。在 Windows 下 GUI 程序输出到 stdout 、stderr 之类的东西都看不到,又不能启动调试器,实在是很无奈。问题出在 GUI 线程被 freeze 掉了,后来发现其实所有的线程都 wait 了,而调用堆栈上显示的是 Qt 在 emit 一个信号的时候进入锁定状态。

从 Qt 4 开始支持多线程之间传递信号,它使用一个 Queue 的机制来传递多线程之间的信号,而程序在 Linux 版的 Qt 下运行得很好,到 Windows 下就立即死锁,我又把队友们的程序整个浏览了一遍,觉得都没有哪里会出现把 GUI 线程锁掉的情况,就不得不怀疑是 Windows 版的 Qt 在这里可能会有 Bug ,可惜我也没有搜索到有用的 Bug 报告一类的。

最后我手动指定 Qt 即使在多线程之间传送信号也不使用 Queue 的方法,然后改动了一下同步,尽量避免线程之间直接调用信号槽会造成的问题。之后 GUI 线程就不会死掉了。不过程序的功能仍然有问题。一个本该被 wake 起来的线程根本没有醒过来,这个线程一开始打开一个文件,然后 wait ,等待别人把它 wake 起来,然后对文件执行一些操作。

经过多次尝试,我们发现程序打开 mp3 和 avi 文件都不行,但是可以打开压缩包。实在是非常郁闷,最后我们把 mp3 打包为压缩文件,发现也不行。终于发现原来所有的影音文件都放在一个路径包含中文的目录下,而压缩包的路径里没有中文。而队友在打开文件的时候由于编码问题 (Qt 内部使用 unicode 编码) 打开含有中文路径的文件失败,但是他却没有做任何判断!导致线程里面直接出错,根本没有 run 起来,就更别谈 wake 了。

总之不管 Typical Chinese Programmer 这个词存在不存在,在真实项目中尽量写出健壮的程序实在是非常必要的,要不然大半的时间就要在痛苦的调试中渡过了。