haskell STM : How to store ThreadID as per their execution sequence

标签 haskell stm

在以下程序中,斐波那契数是根据给定的整数(随机生成)生成的,并将该值存储到 TVar 中。由于不同数字生成斐波那契数的执行时间不同,因此线程不会顺序运行。 我想存储theadID,可能在一个列表中,以检查它们的执行模式。 请帮我。提前致谢。

module Main
where
import Control.Parallel
import Control.Concurrent.STM
import Control.Concurrent
import System.Random 
import Control.Monad
import Data.IORef
import System.IO

nfib :: Int -> Int
nfib n | n <= 2 = 1
   | otherwise = par n1 (pseq n2 (n1 + n2 ))
                 where n1 = nfib (n-1)
                       n2 = nfib (n-2)


type TInt = TVar Int


updateNum :: TInt -> Int -> STM()
updateNum n v = do x1 <- readTVar n
                   let y = nfib v
                   x2 <- readTVar n
                   if x1 == x2
                   then writeTVar n y   
                   else retry

updateTransaction :: TInt -> Int -> IO ()
updateTransaction n v = do atomically $ updateNum n v

incR :: IORef Int -> Int -> IO ()
incR r x = do { v <- readIORef r;                    
      writeIORef r (v - x) }

main :: IO ()
main = do 
    n <- newTVarIO 10
    r <- newIORef 40;
    forM_ [1..10] (\i -> do 
                     incR r i
                     ;v <- readIORef r
                     ;forkIO (updateTransaction n v)
                    )

我想根据所有线程的执行将 [TreadID,FibNo] 存储到一个列表中。假设T1执行了Fib30,T2执行了Fib35,T3->32和T4->40。如果线程的提交顺序如 T1、T3、T2 和 T4,那么我想将 T1-35、T3-32、t2-35、t4-40 存储在列表中。

编辑: 根据@MathematicalOrchid的建议,我修改了 updateTrasaction 如下:-

updateTransaction :: MVar [(ThreadId, Int)] -> TInt -> Int -> IO ()
updateTransaction mvar n v = do
  tid <- myThreadId
  atomically $ updateNum n v
  list <- takeMVar mvar
  putMVar mvar $ list ++ [(tid, v)]

现在我正在尝试打印 main 中该列表中的值

main :: IO ()
main = do 
  ...
  ...
  m <- newEmptyMVar
  ...
  ...
  mv <- readMVar m
  putStrLn ("ThreadId, FibVal : "  ++ " = " ++ (show mv)) 

执行时。无法读取 MVar 值并生成错误

Exception: thread blocked indefinitely in an MVar operation

该怎么办?提前致谢。

最佳答案

你想要类似的东西

updateTransaction :: TInt -> Int -> IO ()
updateTransaction n v = do
  tid <- myThreadId
  putStrLn $ "Start " ++ show tid
  atomically $ updateNum n v
  putStrLn $ "End " ++ show tid

或者也许类似

updateTransaction :: TInt -> Int -> IO ThreadId
updateTransaction n v = do
  atomically $ updateNum n v
  myThreadId

并将 forM_ 更改为 forM


另外,这部分:

do
  x1 <- readTVar n
  ...
  x2 <- readTVar n
  if x1 == x2 ...

如果x1/= x2,那么 GHC 将自动中止并重新启动您的交易。您不需要自己手动检查这一点。事实上,else 分支永远无法执行。这就是 STM 的要点;对于您的事务来说,没有其他人更改您正在查看的数据,因此您不必担心并发写入。


编辑:如果您想记录事务提交的实际顺序,您将需要更多的线程间通信。显然你可以用 STM 做到这一点,但只是为了列出一些东西,也许这可以工作?

updateTransaction :: MVar [(ThreadId, Int)] -> TInt -> Int -> IO ()
updateTransaction mvar n v = do
  tid <- myThreadId
  fib <- atomically $ updateNum n v
  list <- takeMVar mvar
  putMVar mvar $ list ++ [(tid, fib)]

(显然你必须让 updateNum 返回它计算出的数字。)

关于 haskell STM : How to store ThreadID as per their execution sequence,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27273370/

相关文章:

haskell - 为什么 Haskell 缺少 "obvious"类型类

concurrency - 代理没有被执行

concurrency - 选择正确的 Clojure 引用类型以协调写入/读取

haskell - haskell中树上的最大元素?

haskell - 什么是 AllowAmbiguousTypes,为什么在这个 "forall"示例中需要它?

string - haskell 问题 : io string -> [int]

haskell - 读取 Tchan 会导致阻塞或轮询吗?

windows - 如何让 text-icu 在 Windows 上运行?

haskell - Clojure、Haskell(和其他语言)在 STM 中使用了哪些算法?

java - stm实现问题