Bug

bug的表象和背后的原因往往是一种很让人意外的联系,有时候发现背后的原因可能会很搞笑。

我要做的事情就是把10000组数据录入对应的10000个RRD数据库中,每组数据时一个数组,存放着time:value,按照time递增有序。
RRD有个特点就是,同一个time不能录入两次,后面录入数据的time值必须大于前面录入数据的time值。

第一个bug:
我使用多线程的方式进行数据录入。
在子线程里面访问主线程中开辟的内存空间,总会出segment fault,调试了半天不知道为什么。偶然间做了一次小数据量的测试,发现子线程突然不运行了。然后灵光一现,意识到,主线程跑得太快,直接退出了,子线程就根本不会起来。看了一下别人的代码,发现了问题所在。C里面,开启子线程之后,主线程要调用join函数才会等待子线程执行完毕,否则,主线程启动子线程,然后继续执行完自己的代码就会退出,然后整个进程就会退出。而之前的segment fault就是因为主线程正在退出释放资源,而子线程去访问已经释放的内存空间,就出现了segment fault。

第二个bug:
录入10000组数据需要很长时间,所以我在测试时会使用较小的数据量,比如1000组。小数据量时,程序运行很正常,但是一旦我把数据量加大,就会出现数据库更新失败的错误。百思不得其解,在一次错误日志中发现,有一条错误的现象是在往A数据库中存time1的数据时发现time1已经有值了,也就是说之前已经更新过一次了。可是,明明我的数据库只会由一个线程来写,怎么会在它写之前已经有数据了呢?而且这个问题只会在数据量加大的时候出现。经过我的测试,测试数据在2000组以下时不会出错,一旦到了3000组就会出错。我就觉得是不是多线程的时候,各个进程之间跑串掉了。因为更新数据库的操作是调用RRD的库函数,我开始怀疑RRD的update函数是否是线程安全的。
后来在别人的提示下,先把程序用单线程跑,看有没有问题,再试试多线程,因为毕竟单线程要好找bug。我一开始还自信满满的说单线程肯定没问题,结果运行后发现单线程也会出错,问题很快定位到测试数据。我生成的测试数据里面有重复的。也就是对于一些数据库,在同一个time值下生成了两个value,两次向同一个数据库中插入同一个time下的值时就会出错。可是我一行行的看了一下我生成测试数据的代码,就是没找到错误。最后干脆把这段代码重写了一遍,问题依旧。然后就意识到,我生存测试数据时,使用的输入文件中,数据库的名称有重复的。也就是我可能对某一个数据库生成了两组数据。而输入文件的前2000个数据库名称中没有重复的,在2000~3000之间有一个重复的,这也就能解释为什么程序在录入2000组数据时不会出错,一旦到3000组或者更多的数据时就会出错。

Comments