14

我有两个 MVar(以及一个 MVar 和一个 Chan)。我需要从 Chan 中取出东西并处理它们,直到另一个 MVar 不再为空。我的理想解决方案类似于 UNIXselect函数,我传入一个(可能是空的)MVar 列表,线程阻塞直到其中一个已满,然后它返回完整的 MVar。尽我所能尝试,除了用 isEmptyMVar 反复轮询每个 MVar 直到我得到错误之外,我想不出任何办法。这似乎效率低下。

一个不同的想法是使用 throwTo,但它会中断线程中发生的一切,我需要以原子方式完成处理 Chan 的工作。

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

4

2 回答 2

16

Haskell 线程非常便宜,因此您可以通过这种方式解决它,但听起来 STM 更适合您的问题。使用 STM,您可以做到

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

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

您甚至可以使用它来制作自己的基本版本select

select :: [TMVar a] -> STM a
select = foldr1 orElse . map takeTMVar
于 2011-05-04T05:59:38.723 回答
12

使用 STM 版本TChanTVar, 与retryandorElse行为怎么样?

实现 select 是 STM 的优秀功能之一。来自“可组合内存事务”:

除此之外,我们还提供了 orElse,它允许将它们组合为备选方案,以便在第一次重试时运行第二个(第 3.4 节)。这种能力允许线程一次等待许多事情,比如 Unix 的 select 系统调用——除了 orElse 组合得很好,而 select 则不行。


于 2011-05-04T06:00:51.697 回答