墨菲定律的应验
其实第一次接触这个概念是在科幻电影《星际穿越》里,没看过的同学可以去看一下。“墨菲定律”的根本内容是“凡是可能出错的事有很大几率会出错”,指的是任何一个事件,只要具有大于零的机率,就不能够假设它不会发生。
最近呢, 项目里面也有这么个类似的问题出现了。 功能就是就是多线程对数据条目进行管理,根据添加时间对数据项进行删除操作。首先会根据数据项的元信息生成key,按key把数据项的索引信息存入到一张hash表中,数据项的内容存在一个线性的地址池中,索引就是数据项所在地址的下标。一般而言,如果对数据项进行添加删除,需要同时对hash表和地址池进行加锁保护,之前的版本也的确是这样子。结果呢,由于项目的性能不满足需求,同组的同事就希望可以取巧,通过设置标志位的方式,减少对地址池数据项的加锁保护。进行了一系列的操作:
- 在老化之前读取标志位,如果标志位有效,则对hash表加锁,判断是否达到老化时间,删除hash表项,并修改标志为为0,解锁hash表。删除结束。
- 添加的时候加锁查询hash表是否存在表项,如果不存在则添加到hash表中,先解锁hash表。然后再修改标志位为1. 添加结束。
本来以为代码跑的是这样子的。
结果跑成这样了。
按数字过一下,应该就可以发现最终标志位和hash表并不是一致的。标志位为1的时候,hash表中不一定有对应的表项。
多线程,并不是说只有2个线程,是多个线程,这种时序是不可控的。该加锁的东西就加锁,像这种临界资源,一定要确保互斥,不能搞一半放一半的。
这个问题,同事修改之后还是有做了认真的自验的, 我在自己搭建的环境上也帮忙跑了一两天都没有复现出问题,但是测试那边跑个一段时间就出现了。^_^ 写代码的时候先设计好还是很重要的,不能想当然。 后面把锁的范围恢复到之前那样,问题也就不再复现了。。。
行动,才不会被动!
欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。