第十一章 :代码与危机
周日下午两点,江城一中图书馆。
安奕背着书包走进机房时,里面只有三台电脑开着。两台被几个高二学生在用,屏幕上显示着《红色警戒》的游戏界面,鼠标点击声和压低的笑骂声混杂在一起。另一台电脑前坐着一个戴眼镜的女生,正专注地敲着Word文档,大概是准备什么比赛的演讲稿。
他选了最角落那台机器。
开机需要时间。老式的CRT显示器发出低沉的嗡鸣声,屏幕从黑变绿,再慢慢亮起Windows 98的启动画面。机箱风扇转动的声音有些大,带着轴承磨损的杂音。空气里有灰尘、旧书和塑料机箱受热后散发出的特殊气味。
安奕从书包里取出三张软盘。
第一张是系统盘,里面装着他从家里电脑上拷贝过来的编程环境——一个精简版的Visual Basic 6.0,还有几个必要的库文件。第二张是数据盘,存着“磐石”系统已经完成的部分代码。第三张是空白盘,准备用来保存今天的工作成果。
他把系统盘插进软驱。
软驱发出咔哒的读盘声,那种机械转动的声音在安静的机房里格外清晰。等待系统加载的间隙,安奕环顾四周。机房的墙壁刷着淡绿色的漆,有些地方已经剥落,露出下面灰白的水泥。窗户玻璃上蒙着灰尘,午后的阳光透过玻璃照进来,在水泥地面上投下模糊的光斑。
那几个打游戏的学生忽然爆发出一阵欢呼。
“赢了赢了!”
“再来一局!”
管理员从门口探进头来,是个五十多岁的中年男人,穿着洗得发白的蓝色工作服:“小声点!这里是图书馆!”
学生们缩了缩脖子,声音压低了些。
安奕收回目光,屏幕上的编程环境已经加载完成。他插入第二张软盘,打开“磐石”系统的项目文件。
代码在屏幕上展开。
这是“磐石”系统的核心模块——多线程计费引擎。在前世,这种模块用现成的框架几行代码就能搞定。但在2000年,在Windows 98的系统环境下,在VB6这种并不擅长多线程的语言里,要实现稳定可靠的并发计费,需要写大量的底层代码。
安奕活动了一下手指,开始敲键盘。
键盘是那种老式的机械键盘,按键很硬,敲击声清脆。每按下一个键,都能感觉到弹簧的阻力,然后才是键帽触底时轻微的震动。这种触感让他想起前世创业初期,在出租屋里用二手电脑写代码的日子。
那时候也是这样,一个人,一台电脑,一堆问题。
不同的是,这一世他知道这些问题都有答案。
***
时间在代码的流淌中悄然流逝。
窗外的阳光慢慢西斜,光线从窗户的这边移到那边。机房里的学生换了一拨,打游戏的走了,来了几个查资料的高三生,对着屏幕上的高考题库皱眉苦思。戴眼镜的女生也完成了她的文档,收拾东西离开。
安奕完全沉浸在代码的世界里。
他正在调试一个关键的函数——处理多台电脑同时上下机的并发请求。这个函数需要精确地计算时间差,更新数据库,同时还要处理可能出现的异常情况:比如突然断电,比如网络中断,比如用户恶意操作。
逻辑很复杂。
他写了三个嵌套的条件判断,又加了一个错误处理机制。代码行数已经超过两百行,在VB6里这算是相当复杂的函数了。
测试。
第一次运行,程序卡死了。
安奕皱了皱眉,调出调试器。VB6的调试器很简陋,只能单步执行,查看变量值。他一步一步地跟踪代码的执行流程,发现问题出在数据库连接上——当两个线程同时尝试更新同一条记录时,会发生死锁。
需要加锁。
他修改代码,在关键操作前加上互斥锁。这又引入新的问题:如果加锁时间太长,会影响系统响应速度;如果加锁时间太短,又起不到保护作用。
需要找到一个平衡点。
安奕深吸一口气,重新梳理逻辑。他的手指在键盘上快速移动,修改,删除,重写。屏幕上的代码像活物一样变化着,结构越来越清晰,逻辑越来越严密。
窗外传来下课铃声。
下午四点了。
机房里的学生又换了一拨。这次来了几个老师模样的人,大概是来查资料的,坐在靠门的电脑前小声讨论着什么。管理员在门口转了一圈,看了看各台电脑的使用情况,又回到门口的值班桌后坐下,拿起一份报纸。
安奕没有注意这些。
他的全部注意力都集中在屏幕上。函数已经修改到第七版,测试了三次,前两次都有问题,第三次看起来稳定了。
他准备进行最后一次压力测试。
写了一个简单的测试脚本,模拟十台电脑同时上下机的情况。运行。
电脑的CPU使用率瞬间飙升。
老式的奔腾处理器发出更大的嗡鸣声,机箱侧板传来热量。屏幕上的测试数据快速滚动,一行行日志信息闪过。安奕盯着屏幕,眼睛一眨不眨。
第一台,正常。
第二台,正常。
第三台……
屏幕忽然一暗。
不是关机那种黑屏,而是一种诡异的蓝色。
蓝屏。
安奕心里一沉。
Windows 98时代,蓝屏死机是家常便饭。但在这个节骨眼上,在这个公共机房里,在他调试关键代码的时候蓝屏——这麻烦就大了。
蓝色的屏幕上密密麻麻地显示着白色英文字符。
“A fatal exception 0E has occurred at 0028:C0011E36 in VXD VMM(01)+ 00010E36...”
错误代码。
内存地址。
堆栈信息。
安奕快速扫过那些信息,判断出问题所在——他写的多线程函数占用了太多系统资源,导致虚拟内存管理模块崩溃了。这在2000年的硬件条件下很常见,内存只有64MB,跑这种复杂的多线程程序确实吃力。
但管理员不会懂这些。
果然,脚步声从门口传来。
“怎么回事?”
管理员已经放下报纸走了过来。他的脚步声很重,皮鞋踩在水磨石地面上发出嗒嗒的声响。那几个查资料的老师也转过头来看。
安奕保持冷静。
他没有慌乱地按重启键,而是先观察了一下机箱——指示灯还亮着,电源没断。这说明只是系统崩溃,硬件应该没坏。
“电脑蓝屏了。”安奕转过头,语气平静。
管理员已经走到他身边,俯身看向屏幕。他身上的烟草味很重,混合着旧衣服的樟脑丸气味。看到那片刺眼的蓝色,他的眉头皱了起来。
“你干什么了?”
“我在学习编程。”安奕说,“写了一个测试程序,可能占用资源太多了。”
“编程?”管理员的声音里带着怀疑,“你是哪个班的?学生证呢?”
安奕从书包里掏出学生证递过去。
管理员接过,仔细看了看照片,又抬头看了看安奕的脸。“高三(七)班,安奕。”他念出名字,然后把学生证放在电脑桌上,“你一个高三学生,不在教室复习,跑这儿来编什么程?”
“兴趣。”安奕说,“我想考计算机专业。”
这个理由很正当。2000年,计算机是热门专业,很多学生都会提前接触。
但管理员显然不信。
他指着蓝屏的电脑:“兴趣?兴趣能把电脑弄成这样?你知道这一台机器多少钱吗?学校采购的,一台八千多!弄坏了你赔得起吗?”
声音有点大,机房里的其他人都看了过来。
那几个打游戏的学生也暂停了游戏,探头探脑地往这边看。空气忽然变得紧张,能听到机箱风扇转动的声音,能闻到灰尘在光线中飞舞的细微气味。
安奕知道,这时候不能慌。
他站起身,让出座位:“老师,电脑没坏。这只是系统崩溃,重启就好了。”
“重启?”管理员冷笑,“重启就能好?万一硬盘烧了呢?万一主板坏了呢?你负责?”
“我负责。”安奕说得很肯定。
这种肯定让管理员愣了一下。
安奕趁这个机会,伸手按下了机箱上的重启键。动作很轻,但很果断。机箱发出“嘀”的一声,风扇停转,然后又重新启动。
屏幕黑了。
几秒钟后,熟悉的Windows启动画面出现。
管理员盯着屏幕,嘴唇动了动,想说什么又没说出来。他大概没想到这个学生这么镇定,也没想到电脑真的能重启成功。
安奕重新坐下。
等待系统启动的几十秒里,机房安静得能听到呼吸声。那几个打游戏的学生已经不敢出声了,查资料的老师也收回目光,但注意力显然还在这边。
Windows桌面终于出现。
安奕没有急着打开编程环境,而是先打开“我的电脑”,检查系统盘。C盘空间还剩不少,系统文件完整。他又打开设备管理器,检查硬件状态——没有黄色感叹号,所有设备都正常工作。
“您看,硬件没问题。”安奕侧过身,让管理员能看到屏幕。
管理员凑近看了看,脸色稍微缓和,但怀疑还没完全消除:“那你刚才到底在干什么?什么程序能把电脑跑蓝屏?”
“一个多线程测试程序。”安奕说着,插入第一张软盘,打开VB6,“我演示给您看。”
他快速新建了一个项目,写了一个简单的程序——不是“磐石”的核心代码,而是一个教学用的示例:模拟两个线程同时计数。
代码很简单,只有三十几行。
安奕一边写一边解释:“这是创建线程的函数……这是线程执行的代码……这是同步机制,防止数据冲突……”
他的语速平稳,用词专业。
管理员听得半懂不懂,但能看出来这个学生确实懂编程。那些代码不是乱敲的,那些术语不是瞎编的。更重要的是,安奕的态度很坦然——没有心虚,没有躲闪,就像真的只是在学习。
程序写完了。
安奕点击运行。
一个简单的窗口弹出来,上面有两个文本框,里面的数字在同时增长。程序运行得很流畅,CPU使用率只有百分之十几。
“这就是多线程。”安奕说,“我刚才写的测试程序比这个复杂得多,所以把系统跑崩溃了。这是我的问题,我应该在更稳定的环境下测试。”
他承认错误,但把错误归因于“环境不稳定”,而不是“操作不当”。
这个说法很巧妙。
管理员盯着那个运行中的程序看了几秒,又看了看安奕。这个高三学生穿着洗得发白的校服,书包是那种很普通的帆布包,桌上摊开的笔记本上写满了工整的笔记——看起来确实像个好学生。
“你真是自己学的?”管理员问。
“嗯,买了书自学的。”安奕从书包里掏出那本厚厚的《Visual Basic 6.0高级编程》,书页已经翻得有些旧了,里面夹着很多便签。
管理员翻了翻书,看到里面密密麻麻的批注。
字迹工整,思路清晰。有些地方还画了流程图,标注着各种注意事项。
他终于信了。
“自学是好事。”管理员把书还给他,语气完全缓和下来,“但要注意场合。这是学校的公共设备,不能用来做太复杂的测试。万一真弄坏了,确实麻烦。”
“我明白。”安奕点头,“以后我会注意。”
“还有,编程可以,但不能影响其他同学。”管理员指了指那几个打游戏的学生,“更不能像他们那样,用学校的电脑打游戏。”
那几个学生缩了缩脖子。
“我不会的。”安奕说。
管理员又交代了几句,终于转身离开。脚步声渐渐远去,回到门口的值班桌。他重新拿起报纸,但时不时还会往这边看一眼。
危机暂时化解了。
安奕暗暗松了口气。
他关掉那个演示程序,重新插入第二张软盘。但这次他没有立刻打开“磐石”的项目文件,而是先检查了一下软盘里的内容。
文件都在。
但当他尝试打开项目文件时,VB6提示“文件可能损坏”。
安奕心里一紧。
蓝屏死机时,他正在往软盘里保存代码。如果保存过程被中断,文件确实可能损坏。如果“磐石”的核心代码丢了,这几天的功夫就白费了。
他尝试用文本编辑器打开那个文件。
乱码。
大部分内容都损坏了,只有开头几行还能看。安奕快速扫过那些代码,确认是最早写的界面部分,核心的逻辑模块全没了。
损失惨重。
但就在这时,他注意到软盘里还有一个文件,文件名是“AutoSave.bak”。
自动备份。
安奕想起来了——VB6有一个自动备份功能,每隔一段时间会把当前项目保存到一个备份文件里。他刚才太专注,完全忘了这个功能。
他打开那个备份文件。
代码完整地展现在屏幕上。
多线程计费引擎,数据库连接模块,用户界面框架……所有今天写的代码都在,而且是最新的版本。备份时间显示是蓝屏前三分钟——正好是他完成第七版修改,开始压力测试的时候。
文件完好无损。
安奕靠在椅背上,长长地吐出一口气。
后背的衬衫已经被汗水浸湿了,贴在皮肤上,凉飕飕的。机房里开着窗,傍晚的风吹进来,带着四月草木萌发的清新气息。远处操场上传来学生打篮球的呼喊声,砰砰的运球声隐约可闻。
他握着那张软盘。
塑料外壳有些温热,是刚才长时间读写的缘故。软盘的标签上写着“磐石-核心模块”,字是他用蓝色圆珠笔写的,工整清晰。
这张软盘里,存着他这几天的全部心血。
也存着他改变命运的第一步。
但今天的事让他意识到一个问题——在公共机房里开发,风险太大了。今天只是蓝屏,下次万一硬盘真的坏了呢?万一管理员 stricter呢?万一有其他人注意到他在做什么呢?
他需要一个属于自己的开发环境。
一台电脑,不需要多好,但必须完全由他控制。可以随便测试,随便崩溃,不用担心被人怀疑,不用担心损坏公物。
可是钱呢?
家里那台电脑是父亲省吃俭用买的,主要用来给他学习。如果他要再买一台,哪怕是最便宜的二手货,也要一两千块。这对现在的家庭来说,是一笔不小的开支。
而且他没法解释——已经有电脑了,为什么还要再买一台?
安奕把软盘从驱动器中取出,小心地放回书包的夹层里。拉链拉上的声音很轻,但在安静的机房里格外清晰。
窗外,夕阳已经西斜。
橙红色的光线透过灰尘蒙蒙的玻璃,在机房的水磨石地面上投下长长的光影。那几个打游戏的学生终于走了,查资料的老师也收拾东西离开。机房只剩下安奕和门口的管理员。
管理员抬起头:“同学,快闭馆了。”
“好的,马上。”
安奕关闭电脑,收拾书包。键盘上还留着他手指的温度,屏幕慢慢暗下去,最后变成一个黑点,消失。
他背起书包,走出机房。
经过值班桌时,管理员看了他一眼:“以后要测试复杂的程序,最好用自己的电脑。学校的机器老了,经不起折腾。”
“我知道了,谢谢老师。”
安奕走出图书馆。
傍晚的风迎面吹来,带着校园里玉兰花的香气。教学楼里还有学生在自习,窗户透出明亮的灯光。操场上跑步的人三三两两,脚步声在暮色中回荡。
他握了握书包的带子。
软盘就在夹层里,隔着帆布能感觉到那个方形的轮廓。那里面的代码,是“磐石”系统的基石,也是他商业帝国的第一块砖。
但砖需要地基。
而地基,需要一台真正属于他的电脑。
安奕抬起头,看向校门外的街道。路灯已经亮起,昏黄的光晕在暮色中连成一条线。街边的店铺还开着,五金店、小卖部、理发店……还有一家电脑维修店,招牌上写着“二手电脑回收、维修、销售”。
他在店门口停了一下。
橱窗里摆着几台旧电脑,机箱有些锈迹,显示器是那种球面CRT的。价格牌用粉笔写在黑板上:“奔腾II,64MB内存,4.3GB硬盘,1500元”。
一千五。
他摸了摸口袋,里面还有母亲给的二十块钱,加上之前剩下的,总共不到一千。差得远。
但也许,有别的办法。
安奕最后看了一眼橱窗里的电脑,转身走向公交车站。书包随着步伐轻轻晃动,里面的软盘发出细微的摩擦声。
那声音很轻,但在他听来,重如磐石。
