我最近询问了一些关于TVar
的问题,我仍然对活锁感到担忧。
所以我想到了这个结构:
TVar
)。然而,B保持其当前重试的优先级。 我认为这个系统可以防止死锁,但也可以防止饥饿(与TVar
不同)。我想知道是否有人实施了这样一个系统,因为它看起来相当明显,我不想重新发明轮子。
当然,可以很容易地扩展这种方法,以允许用户指定优先级。
优先级可以是(user_supplied_prio, auto_increment)
对,user_supplied_prio
优先,但优先级相同的任务以FIFO顺序解析。
注释/解决方案:
实际上,当我考虑它时,我所描述的内容已经存在于Haskell中,只需使用一个IORef
包裹所有数据,并且仅使用atomicModifyIORef
。 atomicModifyIORef
将确保按顺序应用事务。但是,有人可能认为这意味着数据结构是顺序的(即有效地限于一个线程),但由于懒惰,它实际上是并行的。
要解释这一点,请考虑一个昂贵的函数f
。我们将使用键“foo”将其应用于Data.Map
数据。
这会将(foo -> x)
替换为(foo -> future(f x))
。这个帖子应该继续计算(f x)
实际上是什么,但在此期间我们可以将g应用于“bar”。由于将g应用于“bar”不需要“foo”的结果,我们可以同时解决这个问题。
没有死锁,没有饥饿,最终将处理所有交易(大致按照收到的顺序)。
答案 0 :(得分:1)
您可以设置工作线程以确定的方式处理所有请求,因此没有人会饿死。这种策略可以合理有效并且不受活锁的影响。
-- yes, this is a horrible name
createManagerFactory :: a -> IO ((IO a), IO (((a -> a) -> IO a)))
IO a是一种使用只读STM操作安全快速地查询值的操作。 (a - > a)是修改值的纯函数,因此((a - > a) - > IO a)是一个采用修饰函数,安全修改值并返回新值的动作
运行一次以初始化工厂。
(query, modifierFactory) <- createManagerVactory initValue
然后为每个线程运行此命令以生成新的修饰符。
myModify <- modifierFactory
createManagerFactory将执行以下操作:
modifierFactory会这样做:
工作线程将运行此循环: