安全的迭代一个集合
把同质的东西放入一个容器,然后用迭代器迭代这个容器,把里面的内容逐个取出来处理。这是一个非常常见的需求。但是,这个过程往往也会滋生 bug 。因为,若将容器看成一个对象,那么对其迭代的这个操作很难实现原子性。
非原子性导致了,在迭代过程中,十分有可能对容器本身进行修改。或增加若干元素,或删除若干元素。这些都容易造成迭代过程不正常。
所以,最终我们需要根据需求设计以及实现合理的容器。比如管理消息的消息队列,严格的满足尾进头出,没有删除中间数据的需求,就不会导致 bug 。
那么,如果容器是一个集合怎么办?即,允许向其中增加新的元素,也可以移除某些元素。这种数据结构非常有用。比如向某对象注册若干回调函数,一旦满足条件则依次调用。即设计模式中的 Observer 观察者模式。回调函数就极有可能增加新的观察者或某些老的观察者退出。
简洁的解决方案是,使用一个可变长数组维持这个集合,把数组看成一个队列,永远在一端添加。而删除中间节点,仅仅只是做一个记号(标记成不必再处理的观察者)。
在集合中额外保存一个迭代状态堆栈。每次需要迭代时,从堆栈顶分配一个状态容器出来,负责迭代(里面保存迭代到的位置)。
当迭代尚未完成前,一旦回调函数触发对同一集合的新的迭代请求,状态堆栈会返回一个新的状态容器,保证和前次迭代互不干扰。
迭代完成后,如果当前状态堆栈为空,表示外层再无迭代事务。这个时候,可以一次扫描整个集合,把做过删除标记的节点删除,并压缩整个集合(去掉空巢)。
用 lua 实现以后功能非常简单:代码大约是这样的。
这段代码实现了一个集合,提供了一个安全的迭代器迭代它。使用 enter 把对象置入集合。enter 会返回一个 closure 用于把对象从集合中移除。
当然,用 C 或 C++ 实现一个也不复杂,就不列代码了。
Comments
Posted by: 阿福 | (17) April 29, 2009 10:49 AM
Posted by: wg | (16) April 20, 2009 04:25 PM
Posted by: 双色球 | (15) April 12, 2009 11:53 AM
Posted by: sjinny | (14) March 30, 2009 01:37 AM
Posted by: Cloud | (13) March 30, 2009 12:51 AM
Posted by: sjinny | (12) March 29, 2009 09:36 PM
Posted by: Cloud | (11) March 29, 2009 06:47 PM
Posted by: black | (10) March 29, 2009 06:08 PM
Posted by: sjinny | (9) March 29, 2009 09:06 AM
Posted by: Cloud | (8) March 29, 2009 12:02 AM
Posted by: sjinny | (7) March 28, 2009 10:15 PM
Posted by: Cloud | (6) March 28, 2009 07:14 PM
Posted by: sjinny | (5) March 28, 2009 07:10 PM
Posted by: Cloud | (4) March 28, 2009 06:10 PM
Posted by: lyman | (3) March 28, 2009 09:57 AM
Posted by: analyst | (2) March 28, 2009 09:10 AM
Posted by: 文 | (1) March 28, 2009 03:15 AM