【问题标题】:Can this be done with STM?这可以用STM完成吗?
【发布时间】:2013-07-06 10:39:42
【问题描述】:

免责声明:这可以使用MVar () 作为简单的互斥锁轻松完成。我只是好奇看看STM能不能做到。

我想以原子方式执行以下操作:

  • 读取一些变量。

  • 根据我刚刚阅读的内容决定要执行的 I/O。

  • 执行 I/O。

  • 在变量中记录结果。

具体而言,假设我想跟踪我已读取的输入字节数,并假设在消耗了一定数量的字节后我已达到 EOF。 (好吧,让两个线程同时从同一个文件中读取可能是首先要做的一件虚假的事情,但请跟我一起去......)

显然这不可能是单个 STM 交易;中间有 I/O。显然,将其视为两个不相关的交易也是错误的。 (两个线程可以看到还有一个字节的配额,并且都决定读取那个字节。)

这个问题有很好的解决方案吗?或者 STM 只是这个任务的错误工具?

【问题讨论】:

  • 这能满足您的需要吗? “理发师”可能是您的阅读指针。 stackoverflow.com/questions/16933678/…
  • @DaxFohl 好吧,您可以使用 STM 通过TChan... 将所有 I/O 请求发送到单个线程...这应该可以工作。跨度>
  • 似乎你已经有了一个基本的 Erlang 风格 Actor 模型解决方案的标准用例,这就是理发师通过 STMTChan 实现的。

标签: haskell stm


【解决方案1】:

使用名为 consistentTVar Bool 来跟踪您的 IO 操作是否正在进行中。在运行 IO 操作之前,您将一致设置为 False,在运行 IO 操作之后,您将 consistent 设置为 True。然后,任何依赖于您正在修改的那些 STM 变量的值的操作只需将此子句放在开头:

do b <- readTVar consistent
   check b
   ...

这可确保这些操作只能看到正在修改的变量的一致视图,并且不会在 IO 操作正在进行时运行。

【讨论】:

  • 这个有味道。目前我遇到的问题是互斥锁操作无法运行其他互斥锁操作,因为互斥锁已被使用。我不确定上述方法是否能解决这个问题......
  • 你能解释一下互斥锁的问题吗?
  • 如果您使用MVar () 作为互斥体,并以takeMVar 开始每个函数,则一个函数不能调用另一个函数,因为互斥体已被占用。函数变得不可组合。
  • @MathematicalOrchid 你可以使用TVar Option Integer,并且只有在NoneSome [currentThreadId] 时才能继续
  • @MathematicalOrchid 这是基于锁的编程的普遍问题,基本上就是这样。当您谈到将所有IO 动作发送到某种演员风格的频道时,我认为您可能更正确。听起来这可能会更好地解决您的问题。
【解决方案2】:

我认为您正在寻找 stm-io-hooks 包。

无论您真正想要做什么——是否可以用 STM 的中止/重试语义来表达?换句话说:你能做一个回滚并重复 IO 动作吗? 如果没有,那么我会参考 Gabriel Gonzalez 的回答。

【讨论】:

  • 好吧,所有的 I/O 操作都是 read 操作,所以它们唯一修改的是句柄的状态。如果你能保证没有两个 I/O 操作同时发生,并且每个人总是首先寻找正确的地方......它可能可能工作......但我认为保持 I/ O out of transactions 会更好。
  • @MathematicalOrchid:在那种情况下,我会简单地使用不同的句柄。如果这不是一个选项,您将不得不使用锁定机制(MVar 或 Gabriel 的答案)进行 seek+read。
  • @MathematicalOrchid:我不确定你需要 STM 做什么,但也许你只是在尝试并发。您不需要像在低级语言中那样的互斥锁:在 Haskell 中,您将锁定机制直接应用于资源,例如 MVar Handle 而不是 (MVar (),Handle)。 STM 是一种完全不同的解决并发问题的方法,它使用可以像银行账户之间的货币交易一样中止/恢复/重复的“交易”。我认为读取不可变文件没有用。
  • 我明白了。我使用互斥锁不是为了保护句柄,而是为了保护每次使用句柄时我正在更新的其他内容。但是,正如我所说,它最终变得相当不可组合。我可以修复它,但我只是想知道 STM 是否提供了更好的方法。我怀疑不是,但我想检查一下。
【解决方案3】:

我会说 STM 做不到,这是故意的。如果事务回滚,一段STM代码可以在不同的地方多次重启。如果您运行事务,它会执行 I/O 操作,然后在将结果记录在变量中时回滚会发生什么?

因此,STM 计算必须是纯的,只有添加 STM 原语,例如 STM 可变变量和数组。

【讨论】:

  • 当然,在事务中执行 I/O 是没有意义的;您无法撤消 I/O。但是交易可以用来实现互斥吗?这样做是否明智?
  • @MathematicalOrchid 据我所知,在STM中是无法做到互斥的。不能保证 STM 框架会等待任何事情——它也可以在一个循环中一遍又一遍地重复失败的事务,直到它成功。来自the docs实现可能会阻塞线程,直到它读取的 TVar 之一被更新。 最好的解决方案可能是 comonad 给出的答案- 据我了解,它在成功提交时执行 IO 操作。
  • @MathematicalOrchid 只是一个想法,是否有可能在不冒险陷入僵局的情况下同时实现互斥性和可组合性?
  • 如果只有 1 个资源被锁定。但在一般情况下......不,这不太可能奏效。
  • @MathematicalOrchid 嗯,实际上似乎可能有一个单子解决方案——创建一个单子,在执行之前,尝试从 STM 块中获取组成它的函数的所有互斥锁。通过这种方式,您可以获得所需的精细粒度,但可以防止死锁,只需将您的代码放入 do 块中即可免费获得。看起来很合理,但我的逻辑肯定有缺陷,或者有人已经这样做了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-13
  • 2011-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-13
  • 1970-01-01
相关资源
最近更新 更多