Haskell STM:如何根据线程的执行顺序存储线程ID
在以下程序中,斐波那契数由给定整数(随机生成)生成,该值存储在TVar中。由于生成Fibonacci的执行时间对于不同的数目是不同的,因此线程不会按顺序运行我想将theadID存储在列表中,以检查其执行模式。 请帮帮我。提前谢谢Haskell STM:如何根据线程的执行顺序存储线程ID,haskell,stm,Haskell,Stm,在以下程序中,斐波那契数由给定整数(随机生成)生成,该值存储在TVar中。由于生成Fibonacci的执行时间对于不同的数目是不同的,因此线程不会按顺序运行我想将theadID存储在列表中,以检查其执行模式。 请帮帮我。提前谢谢 module Main where import Control.Parallel import Control.Concurrent.STM import Control.Concurrent import System.Random import Control.
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)
)
怎么办?提前谢谢。您想要类似的东西吗
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)
)
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
并将表单
更改为表单
此外,本部分:
do
x1 <- readTVar n
...
x2 <- readTVar n
if x1 == x2 ...
(显然,您必须让
updateNum
返回它计算的数字。)您知道您的斐波那契实现非常慢吗?或者你想用这个函数作为测试?斐波那契函数作为测试。例如,由于Fibonacci 35将比Fibonacci 25花费更多的时间,因此线程1(Fib 35)的执行时间将比线程2(Fib 25)花费更多的时间。因此,tread2将首先执行,然后是thead1(因为“重试”)。x1是什么让您认为else
分支将执行?如果x1/=x2
,GHC将自动中止交易。@Zeta,请帮我澄清我的疑问。我先将n的值存储到x1中,然后存储到x2中。我这样做是为了检查数据的不一致性,以便在此基础上写入TVar或重试。Haskell STM是否能够在数据不一致的情况下自动重试。正如我所知,在这种情况下,它应该中止。非常感谢您的答复。您正确地说x1/=x2将中止事务。事务可以执行,也可以中止并重新启动。我想根据线程的执行情况将[TreadID,FibNo]存储到所有线程的列表中。假设T1执行了Fib30、T2 Fib35、T3->32和T4->40。如果线程的提交序列像T1、T3、T2和T4,那么我想将T1-35、T3-32、T2-35、T4-40存储在一个列表中。让我试试。谢谢@MathematicalOrchid。根据你的建议,我已经修改了upateTransaction。[即updateTransaction::MVar[(ThreadId,Int)]->TInt->Int->IO()……putMVar MVar$list++[(tid,v)]
(我想存储v而不是fib,因此进行了相应的修改).总的来说,我要声明m来澄清:你不能决定写什么?或者你写了什么,但它没有达到你的预期?你创建了一个空的MVar
。你需要创建一个包含[]
的开始。
updateTransaction :: TInt -> Int -> IO ThreadId
updateTransaction n v = do
atomically $ updateNum n v
myThreadId
do
x1 <- readTVar n
...
x2 <- readTVar n
if x1 == x2 ...
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)]