1

我正在为一项作业编写报告,其中我使用 STM 包实现了并发多核分支定界算法,并且遇到了一个问题。

使用 STM 的实现显然在 IO monad 中,因为它同时使用 STM 的“原子”和并发的“forkIO”,但它是确定性的。尽管使用了共享内存变量,对于相同的输入,函数的最终结果总是相同的。

我的问题是,在退出 IO 时,除了“unsafePerformIO”之外,我还有哪些选择?我是否应该尝试将其从 IO monad 中取出,因为使用多个内核可能会影响其他没有相同确定性保证的并发代码。

我听说过 Par monad 包(虽然没有使用过),但是 IO monad 中存在 STM,为了获得线程安全的全局变量,我唯一可以替代 STM 的方法是 MVars(我知道),它也存在于 IO monad 中。

4

2 回答 2

6

请不要将 unsafePerformIO 与 STM 一起使用。STM 在幕后有副作用,使用 unsafePerformIO 隐藏了这些副作用,使您的代码看似不纯,因此难以或危险重构。更加努力地看看并行包是否会对您有所帮助。

不安全的 STM 操作不安全的一个例子是,当您最终使用嵌套在另一个(可能是更高级别的库)内部的“纯”STM 操作时。例如,<loop>由于嵌套的 STM 操作,下面的代码循环(以 终止)。我记得旧的 GHC 版本崩溃了,但现在似乎无法用 GHC 7.0.1 重现这种行为。

import Control.Concurrent
import Control.Concurrent.STM
import System.IO.Unsafe
import GHC.Conc.Sync

main = newTVarIO 5 >>= runComputation >>= print

runComputation :: TVar Int -> IO Int
runComputation tv = atomically $ do
        let y = getFiveUnsafe tv + 1
        writeTVar tv y
        return y

getFiveUnsafe tv = unsafePerformIO . atomically $ do
        x <- readTVar tv
        writeTVar tv (x + 5)
        return x

(我欢迎其他人编辑和添加更有说服力的例子——我相信存在更好的例子)

于 2011-10-14T15:59:53.617 回答
0

STM并且它的相关函数不能使用,unsafePerformIOforkIO可以,新线程可以atomically安全调用。你可以这样做:

purifiedAlgorithm = unsafePerformIO $ do
  rr <- newEmptyMVar
  forkIO $ concurrentAlgorithm >> putMVar rr
  takeMVar rr
于 2016-08-25T06:30:29.530 回答