2014-11-26 2 views
0

다음 코드 (Pl. myTransaction 참조)에서 특정 지연 후에 값을 읽는 방식으로 TVar n1에서 원자 적으로 읽고 다른 TVar n2를 업데이트하려고합니다. 문제는 하나의 원자 블록을 다른 원자 블록으로 전달할 수 없다는 것입니다. 도와주세요하나의 원자 블록에서 다른 원자 블록으로 값을 전달하는 방법

The last statement in a 'do' loop must be an expression 
    let y = (x + v) 
SimpleSTM1.hs:24:43: Not in scope: 'y' 

:

module SimpleSTM 
where 
import Control.Concurrent.STM 
import Control.Concurrent 
import System.IO.Unsafe 
import System.Random 

type GNum = TVar Int 
updateNum :: GNum -> Int -> STM() 
updateNum n v = writeTVar n v 

myTransaction :: GNum -> GNum -> Int -> IO() 
myTransaction n1 n2 v = do 
    atomically $ do 
     x <- readTVar n1 
     let y = (x + v)  -- Getting Error: Not an expression 

    randomDelay 

    atomically $ updateNum n2 y -- Getting Error: Not in scope: 'y' 


randomDelay = do delay <- getStdRandom(randomR (1,3)) 
    threadDelay (delay * 1000000) 

main :: IO() 
main = do n1 <- newTVarIO 1 
    n2 <- newTVarIO 1 


    n1v <- readTVarIO n1 
    n2v <- readTVarIO n2 

    putStrLn ("n1 = " ++ (show n1v) ++ " n2= " ++ (show n2v)) 


    forkIO (myTransaction n1 n2 1) 
    forkIO (myTransaction n2 n1 2) 
    forkIO (myTransaction n2 n1 3)  

    n1v <- readTVarIO n1 
    n2v <- readTVarIO n2 

    putStrLn ("n1 = " ++ (show n1v) ++ " n2= " ++ (show n2v)) 

코드

는 다음과 같은 오류를 생성합니다. 미리 감사드립니다.

답변

1

당신은

myTransaction :: GNum -> GNum -> Int -> IO() 
myTransaction n1 n2 v = do 
    y <- atomically $ do 
     x <- readTVar n1 
     return (x + v) 
    randomDelay 
    atomically $ updateNum n2 y 

를 실행할 수 있지만,이 원자 트랜잭션을 실행하도록 경고. 즉, 읽기와 연속 쓰기 사이에 업데이트가있어 전체 myTransaction이 비 원자가됩니다. 당신이 정말로 원자 지연 거래를 원하는 경우


, 당신은 unsafePerformIO 종료 몇 시간을내어 순수한 계산을 시뮬레이션

myTransaction :: GNum -> GNum -> Int -> IO() 
myTransaction n1 n2 v = 
    atomically $ do 
     x <- readTVar n1 
     unsafePerformIO randomDelay `seq` return() 
     updateNum n2 (x + v) 

뭔가를 실행할 수 있습니다. unsafePerformIO은 실제로 안전하지 않기 때문에 일반적으로 아무 것도하지 않는 것이 좋습니다. 그러나 순수한 코드로 수행 할 수있는 작업을 시뮬레이트하기 위해이 코드를 사용하면 문제없이 사용할 수 있습니다.

또는 unsafeIOtoSTM도 작동하며 unsafePerformIO과 유사한 경고를 표시합니다.

그러나 "프로덕션"코드에는 트랜잭션 내부에 지연을 추가 할 이유가 없습니다. 따라서 STM 실험을 위해서만이 작업을 수행하려는 것으로 추측하고 있습니다. 아마도 원 자성 보증을 실험적으로 확인하기 위해서 일 것입니다.

+0

Chi. 당신이 말했듯이, 그것은 원자가되지 않아서 제 목적을 해결할 수 없습니다. –

+1

@AmmlanGhosh 그러나 왜 STM 모나드 내에 지연이 필요한지 명확하지 않습니다. 어떤 "진짜"목적이 아니라 그것을 실험하기위한 것일까 요? 그런 다음 어쨌든 "안전하지 않은"물건을 사용하면됩니다. – chi

+0

친애하는 Chi, 새로운 코드를 Answer로 추가했습니다. 트랜잭션을 다시 실행하는 방법을 확인하고 싶습니다. 코드를 확인하십시오. –