2008년 12월 9일 화요일

haskell IORef 를 이용한 두 쓰레드간의 공유 변수

{-
두개의 쓰레드가 하나의 변수를 공유하는 예제를 만들어봤다.

공유한다는것 자체가 값이 변한다는 의미이니 펑셔널한것과는 거리가
멀고 따라서 모나드를 써야 하더라. IORef 가.. 일종의 변수..다른
언어들 처럼 값을 가지는 자리.. place holder 를 만들어주는
개념같구만. 이걸로 IORef a 타입의 값을 만들면 이 값을 통해 값을
읽거나, 바꾸거나 할수 있다.

아직 동기화 부분은 공부를 안해서 아래 코드는 상당히 엉성한데 (동기화
없고, 자식 thread 종료를 기다리는데 sleep 사용) 쓰레드간의 변수
공유라는 원래 목적엔 충분한 예제라고 생각 되는구만.

아.. 애초에 이걸 공부하게 된 이유는 haskell 에서 시그널 핸들러를 달고
있는 도중에 SIGINT 를 잡아도 main loop 에 멈추라는 플래그를 어떻게
전달을 해야 하나 고민을 하다가 작성하게 된것이다.
-}


import Data.IORef
import Control.Concurrent

-- 쓰레드? 두개를 까야지.
-- 두 쓰레드는 변수? var 를 공유하고
-- 한 쓰레드는 줄창 찍어대고
-- 한 쓰레드는 절절히 값을 바꿔보자.
-- 동기화는 아직 몰라서 안걸었삼.
main = do
var <- newIORef 0
foo <- forkIO (threadFoo var)
bar <- forkIO (threadBar var)
threadDelay 100000000 -- 음 낄낄. join 방법을 아직 몰라서..

threadFoo var = do
v <- readIORef var
print v
threadDelay 100
threadFoo var


-- 음 atomicModifyIORef 가 아주 편리해 보이는데 MVar 를 아직 모르니
-- 일단 넘어간다.
threadBar var = do
modifyIORef var (+1)
threadDelay 200
threadBar var




흠. 추가로 적어둔다.
건 위 코드로 테스트 후 만들어본 SIGINT 처리 예제
음. 사실 이런건 전역변수가 더 어울린다고 생각하는데
아직 잘 모르니 뭐..

-- 바쁘게 돌아가며 플래그를 확인하는 메인루프가 있고
-- SIGINT 떨어지면 플래그 값 바꿔서 메인루프 종료시키는
-- 간단한 예제
import System.Posix.Signals
import Data.IORef
import Control.Concurrent

loop stop = do
s <- readIORef stop
putStrLn "busy"
if s then return ()
else loop stop

sigint stop = do
print "SIGNAL"
writeIORef stop True

main = do
stop <- newIORef False
old_handler <- installHandler sigINT
(Catch $ sigint stop)
(Just fullSignalSet)
loop stop



댓글 없음: