并发通用数据结构,没有死锁或资源不足

时间:2012-04-11 07:44:26

标签: haskell concurrency deadlock stm

我最近询问了一些关于TVar的问题,我仍然对活锁感到担忧。

所以我想到了这个结构:

  1. 每个事务都获得唯一的优先级(可能按创建顺序分配)。
  2. 事务尝试对其访问的数据进行读/写锁定。当然,同时读取是可以的,但是一个写入锁定排除了所有其他(读取和写入)。
  3. 假设事务A具有比事务B更高的优先级。如果A持有锁,则B等待,但如果B持有锁并且A想要它,则从锁启动B,A获取它,并且事务B重新启动(如与TVar)。然而,B保持其当前重试的优先级。
  4. 当一个锁被释放并且有等待的事务时,它将进入优先级最高的事务,其余的继续等待。
  5. 我认为这个系统可以防止死锁,但也可以防止饥饿(与TVar不同)。我想知道是否有人实施了这样一个系统,因为它看起来相当明显,我不想重新发明轮子。

    当然,可以很容易地扩展这种方法,以允许用户指定优先级。

    优先级可以是(user_supplied_prio, auto_increment)对,user_supplied_prio优先,但优先级相同的任务以FIFO顺序解析。

    注释/解决方案:

    实际上,当我考虑它时,我所描述的内容已经存在于Haskell中,只需使用一个IORef包裹所有数据,并且仅使用atomicModifyIORefatomicModifyIORef将确保按顺序应用事务。但是,有人可能认为这意味着数据结构是顺序的(即有效地限于一个线程),但由于懒惰,它实际上是并行的。

    要解释这一点,请考虑一个昂贵的函数f。我们将使用键“foo”将其应用于Data.Map数据。

    这会将(foo -> x)替换为(foo -> future(f x))。这个帖子应该继续计算(f x)实际上是什么,但在此期间我们可以将g应用于“bar”。由于将g应用于“bar”不需要“foo”的结果,我们可以同时解决这个问题。

    没有死锁,没有饥饿,最终将处理所有交易(大致按照收到的顺序)。

1 个答案:

答案 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将执行以下操作:

  • 创建一个包含initValue的TVar(称之为valueTVar)。
  • 创建一个包含TVar空集合的TVar(a a(a - &GT; a))(称之为modifyTVarCollection)
  • 返回(原子$ readTVar valueTVar)作为'查询'结果
  • 返回知道modifyTVarCollection
  • 的modifierFactory

modifierFactory会这样做:

  • 创建一个新的TVar(a a(a - &gt; a))(称之为modifyTVar),使用valueTVar的当前值将其初始化为(Left a),并将其添加到modifyTVarCollection
  • 返回一个修改器动作,在一个STM动作中加载(右(a - &gt; a))到modifyTVar,然后在另一个STM动作重试,直到modifyTVar包含(左a)结果值,然后返回该值。

工作线程将运行此循环:

  • 在一个操作中,从modifyTVarCollection中获取所有查询TVars,并检查它们的值。如果它们都包含(左a)值,则重试(这将阻塞直到某个其他线程使用修饰符函数加载其modifyTVar,或者modifierFactory创建新的modifierTVar并将其添加到集合中)。返回包含Right(a - &gt; a)
  • 的所有modifyTVars的列表
  • 迭代所有返回的modifyTVars。对于每个TVar,执行读取修改器功能的操作,安全地执行修改,并将结果作为(左a)
  • 放回到modifyTVar中