在以下程序中,Fibonacci数是从给定的整数(随机生成)生成的,并且该值存储在TVar中。由于生成Fibonacci的执行时间因不同的数量而不同,因此线程不会按顺序运行。 我想存储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]存储到所有线程的List中。假设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 :: IO ()
main = do
...
...
m <- newEmptyMVar
...
...
mv <- readMVar m
putStrLn ("ThreadId, FibVal : " ++ " = " ++ (show mv))
执行时。无法读取MVar值并生成错误
Exception: thread blocked indefinitely in an MVar operation
怎么办?提前谢谢。
答案 0 :(得分:5)
你想要像
这样的东西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-branch可以永远不会执行。这就是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
返回它计算的数字。)