一种无需轮询即可在 MVars 上形成'select'的方法



我有两个MVar(一个MVar和一个Chan)。我得把东西从陈里拿出来处理直到另一个MVar不再是空的。我的理想解决方案是类似UNIX select函数的东西,我传入一个MVar列表(可能是空的),线程阻塞,直到其中一个满了,然后它返回完整的MVar。尽管我可能会尝试,但除了用isEmptyMVar反复轮询每个MVar,直到我得到false之外,我想不出任何方法来做到这一点。

另一种想法是使用throwTo,但它会中断线程中正在发生的事情,并且我需要以原子方式在线程外完成处理作业。

我键入的最后一个想法是为每个MVar创建一个新的forkIO,它试图读取其MVar,然后用自己的实例填充新创建的MVar。然后,原始线程可以阻塞在该MVar上。Haskell线程便宜到可以运行那么多线程吗?

Haskell线程非常便宜,所以您可以用这种方式解决它,但听起来STM更适合您的问题。使用STM,您可以执行

do var <- atomically (takeTMVar a `orElse` takeTMVar b)
   ... do stuff with var

由于retryorElse的行为,此代码尝试获取a,如果失败,则获取b。如果两个都失败,它会阻塞,直到其中一个更新,然后再尝试。

您甚至可以使用它来创建自己的初级版本的select:

select :: [TMVar a] -> STM a
select = foldr1 orElse . map takeTMVar

如何使用STM版本,TChanTVar,与retryorElse的行为?

实现select是STM的一个很好的功能。来自"可组合内存事务":

除此之外,我们还提供orElse,这使得它们可以作为备选组合,所以呢如果第一个重试,则运行第二个(第3.4节)。这种能力允许线程同时等待许多事情,比如Unix选择系统调用-除了orElse组合得很好,而select则没有。


  • orElse in RWH.
  • STM包
  • 关于Haskell的STM的论文

最新更新