2014-12-03 3 views
2

В следующей программе число Фибоначчи генерируется из заданного целого (генерируется случайным образом), и это значение сохраняется в TVar. Поскольку время выполнения для создания Фибоначчи различно для разных чисел, таким образом, потоки не будут выполняться последовательно. Я хочу сохранить theadID, может быть в списке, чтобы проверить их шаблон выполнения. Пожалуйста, помогите мне. Заранее спасибо.Haskell STM: как хранить ThreadID согласно их последовательности выполнения

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 в списке.

Edit: Как было предложено @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 

Что делать? Заранее спасибо.

+1

Вы знаете, что ваша реализация Фибоначчи _really_ медленно? Или вы хотите использовать эту функцию в качестве теста? – Zeta

+0

Функция Фибоначчи как тест. Напр.поскольку Fibonacci 35 займет больше времени, чем Fibonacci 25, и, таким образом, время выполнения для потока 1 (Fib 35) займет больше времени, чем поток 2 (Fib 25). Таким образом, tread2 будет выполняться первым, а затем thead1 (из-за «повтора»). –

+1

'x1 <- readTVar n; ...; x2 <- readTVar n'? Вы знаете, что это совершенно необязательно? – Zeta

ответ

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; в вашей транзакции появится, что никто другой не изменит данные, на которые вы смотрите, поэтому вам никогда не придется беспокоиться о параллельной записи.


Edit: Если вы хотите записать фактический порядок, в котором совершено сделки, вы будете нуждаться в некоторой более межпоточной связи. Очевидно, вы могли бы сделать это с помощью 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 возвращение номер он рассчитывается.)

+0

Большое спасибо за ваш ответ. Вы правильно сказали, что x1/= x2 прервет транзакцию. Транзакция может выполнить или может быть отменена и снова перезапущена. Я хочу сохранить [TreadID, FibNo] в список для всех потоков в соответствии с их исполнением. Предположим, что T1 выполнил Fib30, T2 Fib35, T3-> 32 и T4-> 40. И если последовательность фиксации потоков, таких как T1, T3, T2 и T4, тогда я хочу сохранить T1-35, T3-32, t2-35, t4-40 в списке. –

+0

Спасибо @MathematicsOrchid. Дай мне попробовать. –

+0

Thank @MathematicsOrchid. По вашему совету я изменил upateTransaction. [Т.е. 'updateTransaction :: MVar [(ThreadId, Int)] -> TInt -> Int -> IO() ... .... putMVar mvar $ list ++ [(tid, v)]' (я хочу сохранить v вместо fib, таким образом, соответствующим образом изменяются). В основном я объявляю 'm <- newEmptyMVar' и называю' forkIO (updateTransaction m n v) '. Но я не смог напечатать значения 'm' в основном. Пожалуйста помоги. –

 Смежные вопросы

  • Нет связанных вопросов^_^