> Erlang中文手册 > safe_fixtable/2 锁定一定 ETS 表使其可以安全遍历

ets:safe_fixtable/2

锁定一定 ETS 表使其可以安全遍历

用法:

safe_fixtable(Tab, Fix) -> true

锁定一个类型是 set,bag 或 duplicate_bag 的表,使其可以安全遍历表里的数据

在一个进程里调用 ets:safe_fixtable(Tab, true) 可以锁定一个表,直到在进程里调用 ets:safe_fixtable(Tab, false) 才会解锁,或进程崩溃。

如果同时有几个进程锁定一个表,那么表会一直保持锁定状态,直到所有进程都释放它(或崩溃)。有一个引用计数器记录着每个进程的操作,有 N 个持续的锁定操作必须有 N 个释放操作,表才会真正被释放。

当一个表被锁定,一序列的 ets:first/1 和 ets:next/2 的调用都会保证成功执行,并且表里的每一个对象数据只返回一次,即使在遍历的过程中,对象数据被删除或插入。在遍历过程中插入到表里的新数据可能由 ets:next/2 返回(这取决有键的内部顺序)。

TraversalFun = fun
    TraversalFun(_AccTab, '$end_of_table') ->
        traversal_done;
    TraversalFun(AccTab, AccKey) ->
        case ets:lookup(AccTab, AccKey) of
            [{Key, _Val}] ->
                ets:delete(AccTab, Key);
            _ ->
                true
        end,
        TraversalFun(AccTab, ets:next(AccTab, AccKey))
end,
Tab = ets:new(ets_tab, [named_table, set]),
ets:insert(Tab, [{apple, 1}, {pear, 2}, {orange, 3}, {grape, 4}, {watermelon, 5}]),
ets:safe_fixtable(Tab, true),
TraversalFun(Tab, ets:first(Tab)),
ets:safe_fixtable(Tab, false).

一个被锁定的表是不会有被删除的对象数据从表里被实际删除,直到它被释放。如果一个进程锁定一个表,并不释放它,那些已删除的对象数据所占用的内存将永远不会得到释放。对表操作的性能也会显著降低。

可以使用 ets:info/2 来查看有哪些进程锁定了表。有很多进程锁定表的系统需要一个监控来给那些锁定表很长时间的进程发送警告消息。

对于 ordered_set 类型的表,ets:safe_fixtable/2 是没必要的,因为 ets:first/1 和 ets:next/2 将总会调用成功。