ãœãããŠã§ã¢ãã©ã³ã¶ã¯ã·ã§ã³ã¡ã¢ãª
STMã¯ã競äºåã®ããããŒã¿ã¢ãã«ãããã°ã©ãã³ã°ããããã®ã¢ãããŒãã§ãã ããã§ã®ç«¶äºã¯ãã¢ãã«ã®ããŸããŸãªéšåãäºãã«ç¬ç«ããŠç°ãªãã¹ã¬ããã§æŽæ°ãããå ±æãªãœãŒã¹ã®ç«¶åããã©ã³ã¶ã¯ã·ã§ã³ã䜿çšããŠè§£æ±ºãããããšã§ãã ãã©ã³ã¶ã¯ã·ã§ã³ã¯ããŒã¿ããŒã¹ã®ãã©ã³ã¶ã¯ã·ã§ã³ãšäŒŒãŠããŸãããããã€ãã®éãããããŸãã ã³ãŒãå ã®ããŒã¿ã®äžéšãå€æŽãããšããŸãã æŠå¿µçã«ã¯ãã³ãŒããã¢ãã«ã«çŽæ¥æžã蟌ãŸããã®ã§ã¯ãªããå¿ èŠãªéšåã®ã³ããŒã§æ©èœãããšæ³å®ã§ããŸãã æåŸã«ãSTMãšã³ãžã³ã¯ãã©ã³ã¶ã¯ã·ã§ã³ãéããæåã«é¢å¿ã®ããã¢ãã«ã®éšåã誰ã«ãã£ãŠãå€æŽãããŠããªãããšã確èªããŸãã å€æŽããŸããã§ãããïŒ ããŠãæ°ããå€ã¯ä¿®æ£ãããŸãã ããªãã®åã«èª°ãã管çããŸãããïŒ ããã¯ç«¶åã§ããæ°ããããŒã¿ã§èšç®ãåéããŠãã ããã æŠç¥çã«ã¯ãããã¯æ¬¡ã®ããã«è¡šãããšãã§ããŸãã
ããã§ãã¢ãããã¯æäœã¯ã¹ã¬ããã«ãã£ãŠäžŠåã«å®è¡ãããŸãããã¢ãã«ã®å¯å€éšåãžã®ã¢ã¯ã»ã¹ããããã¯ãããã©ã³ã¶ã¯ã·ã§ã³å ã§ã®ã¿ã³ããããããŸãã
STMã«ã¯ããŸããŸãªããªãšãŒã·ã§ã³ããããŸãããæåãªäœåãComposable Memory Transactionsãã§ææ¡ããããã®ã«ã€ããŠå ·äœçã«ã話ããŸãã
- ããŒã¿ã¢ãã«ã®æŠå¿µãšãã®äžã®èšç®ã¯åé¢ãããŠããŸãã
- ã³ã³ãã¥ãŒãã£ã³ã°ã¯STMã¢ããã§ãããFPãã©ãã€ã ã«å®å šã«æºæ ããŠæ§æã§ããŸãã
- æåã§èšç®ãåéãããšããæŠå¿µããããŸãïŒåè©Šè¡ïŒã
- æåŸã«ãHaskellã®åªããå®è£ ããããŸãããããã¯èæ ®ããŸããããèªåã®ã€ã³ã¿ãŒãã§ã€ã¹ã®ãããªãã®ã«çŠç¹ãåãããŸãã
ã¢ãã«ã«ã¯ãä»»æã®ããŒã¿æ§é ã䜿çšã§ããŸãã STMã©ã€ãã©ãªã¯ãå€æ°ïŒ TVar ïŒããã¥ãŒïŒ TQueue ïŒãé åïŒ TArray ïŒãªã©ãããŸããŸãªããªããã£ããæäŸããŸãã ãã©ã³ã¶ã¯ã·ã§ã³å€æ°-TVar'iïŒ "ã¯ãªãã¿ãŒ"ïŒ-ã¯ãæ¬æ ŒçãªSTMã«ã¯ãã§ã«æå°éã§ãããä»ã®ãã¹ãŠã¯ããããéããŠè¡šçŸãããŠãããšæšæž¬ã§ããŸãã
ããšãã°ã é£äºããå²åŠè ã®åé¡ãèããŠã¿ãŸãããã ãã©ãŒã¯ã¯ã競äºåã®ããã¢ã¯ã»ã¹ãæ§ç¯ããããã«å¿ èŠãªå ±éãªãœãŒã¹ãšããŠæ³åã§ããŸãã
data ForkState = Free | Taken type TFork = TVar ForkState data Forks = Forks { fork1 :: TFork , fork2 :: TFork , fork3 :: TFork , fork4 :: TFork , fork5 :: TFork }
ãã®ã¢ãã«ã¯æãåçŽã§ããåãã©ãŒã¯ã¯ç¬èªã®ãã©ã³ã¶ã¯ã·ã§ã³å€æ°ã«æ ŒçŽããããã¢ã§äœæ¥ããå¿ èŠããããŸãïŒ ïŒfork1ãfork2ïŒãïŒfork2ãfork3ïŒã...ïŒfork5ãfork1ïŒ ã ãããããã®ãããªæ§é ã¯ãã£ãšããŸãæ©èœããŸããã
type Forks = TVar [ForkState]
å ±æãªãœãŒã¹ã¯1ã€ãããªããå²åŠçãªã¹ããªãŒã ã5ã€ããå Žåããããã¯é çªã«ã³ãããããæš©å©ãåãåããŸãã ãã®çµæã1人ã®å²åŠè ã ããé£äºãããä»ã®4人ãèãã次ã«å¥ã®äººãé£äºãããŸãããçè«çã«ã¯5ã€ã®ãã©ãŒã¯ã§2人ãåæã«é£äºãããããšãã§ããŸãã ãããã£ãŠãæãæåŸ ãããåäœãæäŸãã競åã¢ãã«ãäœæããå¿ èŠããããŸãã STMã¢ããã®èšç®ã¯ãåå¥ã®ã¯ãªãŒãã£ãŒãã©ãŒã¯ãæã€ã¢ãã«ã«å¯ŸããŠã©ã®ããã«èŠãããã瀺ããŸãã
data ForkState = Free | Taken type TFork = TVar ForkState takeFork :: TFork -> STM Bool takeFork tFork = do forkState <- readTVar tFork when (forkState == Free) (writeTVar tFork Taken) pure (forkState == Free)
ãã©ã°ã解æŸãããæ£åžžã«ãååŸããããå Žåãã€ãŸãtForkãäžæžããããå Žåãé¢æ°ã¯Trueãè¿ããŸãã ãã©ã°ããã§ã«åäœããŠããå Žåã¯ãFalseã«ãªãã觊ããããŸããã 次ã«ãããã€ãã®ãã©ãŒã¯ã«ã€ããŠèããŸãã 5ã€ã®ç¶æ³ããããŸãã
- äž¡æ¹ãšãç¡æã§ã
- å¿ãããŸãŸïŒå·Šé£ïŒãå³ã¯ç¡æ
- å·Šãç¡æãå³ãå¿ããïŒå³é£ïŒ
- äž¡æ¹ãšãå¿ããïŒé£äººïŒ
- ã©ã¡ããå¿ããïŒå²åŠè ã«ããïŒ
ç§ãã¡ã¯ä»ãç§ãã¡ã®å²åŠè ã«ããäž¡æ¹ã®åå²ã®åãæ¹ãæžããŸãïŒ
takeForks :: (TFork, TFork) -> STM Bool takeForks (tLeftFork, tRightFork) = do leftTaken <- takeFork tLeftFork rightTaken <- takeFork tRightFork pure (leftTaken && rightTaken)
ãã®ã³ãŒãã§ã¯ã1ã€ã®ãã©ã°ïŒããšãã°ãå·Šã®ãã©ã°ïŒã䜿çšã§ããŸãããå¥ã®ãã©ã°ïŒããšãã°ãé£äººãå æããŠããããšãå€æããå³ã®ãã©ã°ïŒã¯äœ¿çšã§ããªãããšã«æ°ä»ããããããŸããã ãã¡ãããã®å Žåã takeForksé¢æ°ã¯Falseãè¿ããŸããã1ã€ã®ãã©ãŒã¯ããŸã å²åŠè ã®æäžã«ãããšããäºå®ã¯ã©ãã§ããããïŒ åœŒã¯äžäººã§é£ã¹ãããšãã§ããªãã®ã§ãå ã«æ»ããªããã°ãªããããããã°ããèãç¶ããªããã°ãªããŸããã ãã®åŸãäž¡æ¹ã®ãã©ãŒã¯ãç¡æã«ãªãããšãæåŸ ããŠãããäžåºŠè©Šãããšãã§ããŸãã
ããããSTMã®èŠ³ç¹ããã®ããããããã¯ãã¯ãä»ã®ç«¶åæ§é ã®èŠ³ç¹ããããç°ãªãæ¹æ³ã§å®è£ ãããŸãã tLeftForkãštRightForkã®äž¡æ¹ã®å€æ°ã¯ãä»ã®å²åŠè ã«ãã£ãŠåããªãœãŒã¹ã«æ¥ç¶ãããŠããªãããŒã«ã«ã³ããŒã§ãããšæ³å®ã§ããŸãã ãããã£ãŠããã©ã°ãã眮ããããšã¯ã§ããŸãããã倱æããããšãèšç®ã«äŒããããšãã§ããŸãã ãã®å Žåã1ã€ã®ãã©ãŒã¯ã¯å ±æãªãœãŒã¹ã«æžã蟌ãŸããŸãã-ãšã«ããã takeForkã®åŒã³åºããæåããŸããã§ãã ã ããã¯éåžžã«äŸ¿å©ã§ãããHaskelian STMå®è£ ãä»ã®ãã®ããåºå¥ããã®ã¯ãçŸåšã®ã¢ããèšç®ã®ããã£ã³ã»ã«ãæäœã§ãã ãã£ã³ã»ã«ããããã®ç¹å¥ãªåè©Šè¡æ¹æ³ããããŸããããã䜿çšããŠtakeForksãæžãæããŸãããã
takeForks :: (TFork, TFork) -> STM () takeForks (tLeftFork, tRightFork) = do leftTaken <- takeFork tLeftFork rightTaken <- takeFork tRightFork when (not leftTaken || not rightTaken) retry
äž¡æ¹ã®åå²ç¹ãå²åŠè ã«ãã£ãŠäžåºŠã«ååŸãããå Žåãèšç®ã¯æåããŸãã ãã以å€ã®å Žåã¯ãäžå®ã®ééã§äœåºŠãåèµ·åããŸãã ãã®ããŒãžã§ã³ã§ã¯ãäž¡æ¹ã®ãªãœãŒã¹ãæ£åžžã«ãã£ããã£ããããã©ãããç¥ãå¿ èŠããªãããã Boolãè¿ããŸããã é¢æ°ãå®è¡ãããèšç®ããã¡ã€ã«ããªãå Žåãæ£åžžã«å®è¡ãããããšãæå³ããŸãã
åå²ç¹ããšã£ãåŸãããšãã°å²åŠè ããé£ã¹ããç¶æ ã«ãããªã©ãäœãä»ã®ããšãããå¿ èŠãããã§ãããã takeForksãåŒã³åºããåŸã«ãããè¡ãã ãã§ãSTMã¢ããã¯ãã¯ãªãŒãã£ãŒãã®æ¡ä»¶ãäžè²«ããŠããããšã確èªããŸãã
data PhilosopherState = Thinking | Eating data Philosopher = Philosopher { pState :: TVar PhilosopherState , pLeftFork :: TFork , pRrightFork :: TFork } changePhilosopherActivity :: Philosopher -> STM () changePhilosopherActivity (Philosopher tState tLeftFork tRightFork) = do state <- readTVar tState case state of Thinking -> do taken <- takeForks tFs unless taken retry -- Do not need to put forks if any was taken! writeTVar tAct Eating pure Eating Eating -> error "Changing state from Eating not implemented."
ãã®ã¡ãœããã®å®å šãªå®è£ ã¯æŒç¿ãšããŠæ®ããæåŸã®ããã·ã³ã°ãªã³ã¯ã«ã€ããŠæ€èšããŸãã ãšããããããã©ã³ã¶ã¯ã·ã§ã³ã¢ãã«ã®ããžãã¯ã®ã¿ã説æããŸããããç¹å®ã®TVarããŸã äœæããŠããããäœãéå§ããŠããŸããã ããããã£ãŠã¿ãŸãããïŒ
philosoperWorker :: Philosopher -> IO () philosoperWorker philosopher = do atomically (changePhilosopherActivity philosopher) threadDelay 5000 philosoperWorker philosopher runPhilosophers :: IO () runPhilosophers = do tState1 <- newTVarIO Thinking tState2 <- newTVarIO Thinking tFork1 <- newTVarIO Free tFork2 <- newTVarIO Free forkIO (philosoperWorker (Philosopher tState1 tFork1 tFork2)) forkIO (philosoperWorker (Philosopher tState2 tFork2 tFork1)) threadDelay 100000
ã¢ãããã¯ã«ïŒSTM a-> IO aã³ã³ãããŒã¿ãŒã¯ã STMã¢ããã§ã¢ãããã¯ã«èšç®ãå®è¡ããŸãã ã¿ã€ãããã競åã¢ãã«ã§åäœããçŽç²ãªéšåã¯ã IOã¢ããã®ã¯ãªãŒã³ã§ãªãã³ã³ãã¥ãŒãã£ã³ã°ããåé¢ãããŠããããšãããããŸãã STMã³ãŒãã¯å¹æããããŸããã ããè¯ã-ãŸã£ãããããŸãããããããªããšãåèµ·åæã«ããã€ãã®å¥åŠãªçµæãåŸãããŸããããšãã°ããã¡ã€ã«ã«æžã蟌ãã å Žåãå Žåã«ãã£ãŠã¯åœã®ãšã³ããªãååŸã§ããŸããããã®ãšã©ãŒããã£ããããã®ã¯éåžžã«å°é£ã§ãã ãããã£ãŠã STMã¢ããã«ã¯çŽç²ãªèšç®ãããªãããã®å®è¡ã¯ã¢ãããã¯æäœã§ãããšæ³å®ã§ããŸãããä»ã®èšç®ã¯ãããã¯ããŸããã TVar newTVarIO :: a-> IOïŒTVar aïŒãäœæããé¢æ°ãæ±ããŠããŸãããçŽç²ãªã³ã³ãããŒã¿newTVar :: a-> STMïŒTVar aïŒã䜿çšããŠSTMå ã§æ°ããTVarãäœæããããšã劚ãããã®ã¯ãããŸããã å¿ èŠãªãã£ãã ãã§ãã æ°é ãã®ãã人ã¯ããã©ãŒã¯ã ããå ±æãªãœãŒã¹ã§ãããå²åŠè èªèº«ã®ç¶æ ã䟿å®äžTVarã§ã©ãããããŠããããšã«æ°ä»ãã§ããã ã
ãŸãšãããšã STMã®æå°å®è£ ã«ã¯ã TVarãæäœããããã®æ¬¡ã®æ©èœãå«ãŸããŠããå¿ èŠããããŸãã
newTVar :: a -> STM (TVar a) readTVar :: TVar a -> STM a writeTVar :: TVar a -> a -> STM ()
èšç®ã®å®è¡ïŒ
atomically :: STM a -> IO a
æåŸã«ãèšç®ãåéããæ©èœã¯éåžžã«ãã©ã¹ã«ãªããŸãã
retry :: STM a
ãã¡ãããã©ã€ãã©ãªã«ã¯ãããšãã°STMã® Alternativeåã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãªã©ãä»ã«ãéåžžã«å€ãã®äŸ¿å©ãªæ§æèŠçŽ ããããŸãããç¬ç«ããåŠç¿ã®ããã«æ®ããŸãããã
ããªãŒã¢ããã®STM
é©åã«åäœããSTMãå®è£ ããããšã¯é£ãããšèããããŠãããã³ã³ãã€ã©ãŒããã®ãµããŒããããã°è¯ãã§ãã HaskellãšClojureã®å®è£ ã¯çŸæç¹ã§æé«ã§ãããä»ã®èšèªã§ã¯STMã¯çŸå®çã§ã¯ãªããšèããŠããŸãã åœä»€åèšèªã§èšç®ãåéããå¹æãå¶åŸ¡ããããšãã§ããã¢ããSTMã¯ååšããªããšæ³å®ã§ããŸãã ããããããã¯ãã¹ãŠæ idleãªæšè«ã§ãããç§ã¯ééã£ãŠãããããããŸããã æ®å¿µãªãããä»ã®ãšã³ã·ã¹ãã ã¯èšããŸã§ããªãã stm haskelã©ã€ãã©ãªãŒã®å éšããç解ã§ããŸããã ããã§ããã€ã³ã¿ãŒãã§ã€ã¹ã®èŠ³ç¹ããèŠããšããã«ãã¹ã¬ããç°å¢ã§ã³ãŒããã©ã®ããã«åäœãããã¯æããã§ãã ãããŠãã€ã³ã¿ãŒãã§ãŒã¹ïŒãµããžã§ã¯ãæåèšèªïŒãšäºæ³ãããåäœã®ä»æ§ãããå Žåãããã¯ãã§ã«ãããªãŒã¢ããã䜿çšããŠç¬èªã®STMãäœæããããšããã®ã«ååã§ãã
ã ããã ç¡æã®ã¢ãã ã Freeã¢ããäžã«æ§ç¯ãããDSLã«ã¯ã次ã®ç¹æ§ããããŸãã
- äžå çã«æ§æå¯èœãªçŽç²ãªDSLãã€ãŸãæ¬åœã«æ©èœããŸãã
- ãã®ãããªDSLã®ã³ãŒãã«ã¯ããµããžã§ã¯ãé åã«å ããŠäœåãªãã®ã¯å«ãŸããŸãããã€ãŸããèªã¿ããããç解ãããããšããããšã§ãã
- ã€ã³ã¿ãŒãã§ã€ã¹ãšå®è£ ã¯å¹æçã«åé¢ãããŠããŸãã
- ããã€ãã®å®è£ ããããå®è¡æã«çœ®ãæããããšãã§ããŸãã
ç¡æã®ã¢ããã¯éåžžã«åŒ·åãªããŒã«ã§ããã Inversion of Controlãå®è£ ããããã®ãæ£ãããçŽç²ã«æ©èœçãªã¢ãããŒããšèããããšãã§ããŸãã ç§ã®èãã§ã¯ããµããžã§ã¯ãé åã®åé¡ã¯ãFree-monadic DSLã®å©ããåããŠè§£æ±ºããããšãã§ããŸãã ãã®ãããã¯ã¯éåžžã«åºç¯å²ã§ãããé¢æ°åããã°ã©ãã³ã°ã®ãœãããŠã§ã¢èšèšãšã¢ãŒããã¯ãã£ã®å€ãã®åé¡ã«é¢ä¿ããŠãããããä»ã®è©³çŽ°ã¯å³ããçããŸãã 奜å¥å¿peopleçãªäººã¯ãã€ã³ã¿ãŒãããäžã®å€æ°ã®æ å ±æºããŸãã¯ç¡æã®ã¢ãããç¹å¥ãªæ³šæãæãããŠããç§ã®åæ¬ã®Functional Design and Architectureã«ç®ãåããããšãã§ããŸãã
ã§ã¯ã stm-freeã©ã€ãã©ãªã®ã³ãŒããèŠãŠã¿ãŸãããã
STMã¯ãã©ã³ã¶ã¯ã·ã§ã³ã¢ãã«ãäœæããããã®ãµããžã§ã¯ãæåèšèªã§ãããããã¯ãªãŒã³ã§å調ã§ããæå°éã®STMã®å Žåãç¡æDSLã«ã¯TVarãæäœããããã®åãã¡ãœãããå«ãŸããŠããå¿ èŠããããŸããç¡æã®ã¢ããã ãŸããTVarãšã¯äœããå€æããŸãã
type UStamp = Unique newtype TVarId = TVarId UStamp data TVar a = TVar TVarId
ãã¯ãªãŒãã£ãŒããåºå¥ããå¿ èŠããããããåã€ã³ã¹ã¿ã³ã¹ã¯äžæã®å€ã§èå¥ãããŸãã ã©ã€ãã©ãªãŠãŒã¶ãŒã¯ãããç¥ãå¿ èŠã¯ãããŸãããTVaraåã䜿çšããããšãæåŸ ãããŸãã ãã®ã¿ã€ãã®å€ãæ±ãããšã¯ãå°ããªSTMã®åäœã®ååã§ãã ãããã£ãŠãé©åãªæ¹æ³ã§ADTãå®çŸ©ããŸãã
data STMF next where NewTVar :: a -> (TVar a -> next) -> STMF next WriteTVar :: TVar a -> a -> next -> STMF next ReadTVar :: TVar a -> (a -> next) -> STMF next
ãããŠãããã§ãã詳现ã«æ»åšããå¿ èŠããããŸãã
ãªããããè¡ãå¿ èŠãããã®ã§ããïŒ èŠããã«ãFree Monadã¯äœããã®eDSLã®äžã«æ§ç¯ããå¿ èŠããããšããããšã§ãã æãç°¡åãªèšå®æ¹æ³ã¯ãå¯èœãªã¡ãœãããADTã³ã³ã¹ãã©ã¯ã¿ãŒã®åœ¢åŒã§å®çŸ©ããããšã§ãã ãšã³ããŠãŒã¶ãŒã¯ãã®ã¿ã€ãã§ã¯åäœããŸããããããã䜿çšããŠãäœããã®å¹æã®ããã¡ãœããã解éããŸãã æããã«ãNewTVarã¡ãœããã¯ããæ°ããTVarãäœæãããçµæãšããŠè¿ãããããšããçµæã§è§£éãããå¿ èŠããããŸãã ããããããšãã°ããŒã¿ããŒã¹ããã°ãžã®æžã蟌ã¿ããŸãã¯å®éã®STMãžã®åŒã³åºããªã©ãäœãä»ã®ããšãè¡ãã€ã³ã¿ãŒããªã¿ãŒãäœæã§ããŸãã
ãããã®ã³ã³ã¹ãã©ã¯ã¿ã«ã¯ã解éããå¿ èŠããããã¹ãŠã®æ å ±ãå«ãŸããŠããŸãã NewTVarã³ã³ã¹ãã©ã¯ã¿ãŒã«ã¯ããŠãŒã¶ãŒå®çŸ©ã®å€aãå«ãŸããŠããã解éæã«ãã®å€ãæ°ããTVarã«å ¥ããŸãã ãããåé¡ã¯ã NewTVarãžã®åŒã³åºãããšã«aãç¬èªã®ãã®ã§ãªããã°ãªããªãããšã§ã ã 次ã®aã«STMFãèšè¿°ããå Žåãããã€ãã®NewTVaråŒã³åºããçµã³ä»ããããŠãããã¹ãŠã®ã³ãŒãã«æ¢ã«å ±éããŠããŸãïŒ
data STMF next a where NewTVar :: a -> (TVar a -> next) -> STMF next
ããããããã¯ç¡æå³ã§ãããªããªããç§ãã¡ã¯ãŸã ä»»æã®åã«NewTVarã䜿çšãããããã§ãã ãããã£ãŠãç¹å®ã®ã¡ãœããã®ã¿ã®ããŒã«ã«å¯èŠæ§ã§aãåé€ããŸãã
ã泚æ å®éãProof of Conceptã®äœæ¥ãé«éåããããã«ãã·ãªã¢ã«åã§ããããã«aãå ¥åããããã«å¶éãããŠããŸãïŒ aesonã©ã€ãã©ãªã®ToJSON / FromJSONã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ïŒã å®éããããã®ããŸããŸãªã¿ã€ãã®TVarããããã«ä¿åããå¿ èŠããããŸããã Typeable / Dynamic ãç¹ã«HListsãå°ç¡ãã«ããããããŸããã å®éã®STMã§ã¯ãã¿ã€ãaã¯é¢æ°ã§ãã絶察ã«äœã§ãããŸããŸããã ãŸãããã®åé¡ã«ã€ããŠã¯åŸã»ã©å¯ŸåŠããŸãããã®æ¬¡ã®ãã£ãŒã«ãã¯ã©ã®ãããªãã®ã§ããïŒ ããã§ã¯ãFree Monadããã®èŠæ±ã«å¿ããŸãã 圌女ã¯çŸåšã®ã¡ãœããã®ç¶ç¶ãã©ããã«ä¿åããå¿ èŠãããã 次ã®ãã£ãŒã«ãã¯åœŒå¥³ã«é©ããŠããªã-ADTã¯ãã®ãã£ãŒã«ãã®ãã¡ã³ã¯ã¿ãŒã§ããã¹ãã ã ãããã£ãŠã NewTVarã¡ãœããã¯TVar aãè¿ãå¿ èŠããããç¶ç¶ïŒTVar a-> nextïŒã¯æ°ããå ¥åå€æ°ãåŸ ã£ãŠããã ãã§ããããšãããããŸãã äžæ¹ã WriteTVarã¯æçšãªãã®ãäœãè¿ããªããããç¶ç¶ã¯nextåã§ããã€ãŸããäœãå ¥åããããšã¯ãããŸããã STMFã¿ã€ãã®ãã¡ã³ã¯ã¿ãŒã®äœæã¯ç°¡åã§ãã
instance Functor STMF where fmap g (NewTVar a nextF) = NewTVar a (g . nextF) fmap g (WriteTVar tvar a next ) = WriteTVar tvar a (g next) fmap g (ReadTVar tvar nextF) = ReadTVar tvar (g . nextF)
ããèå³æ·±ã質åã¯ãSTMã®ã«ã¹ã¿ã ã¢ãããæçµçã«ã©ãã«ãããã§ãã ããã«ãããŸãïŒ
type STML next = Free STMF next
STMFåãFreeåã§ã©ãããã ããã«å¿ èŠãªãã¹ãŠã®ã¢ããããããã£ãè¿œå ããŸããã ããåºãã®STMFã¡ãœããã®äžã«äžé£ã®äŸ¿å©ãªã¢ããé¢æ°ãäœæããã ãã§ãã
newTVar :: ToJSON a => a -> STML (TVar a) newTVar a = liftF (NewTVar a id) writeTVar :: ToJSON a => TVar a -> a -> STML () writeTVar tvar a = liftF (WriteTVar tvar a ()) readTVar :: FromJSON a => TVar a -> STML a readTVar tvar = liftF (ReadTVar tvar id)
ãã®çµæãTVarã®åœ¢åŒã®ãã©ã³ã¶ã¯ã·ã§ã³ã¢ãã«ã§æ¢ã«åäœããããšãã§ããŸãã å®éãé£äºã®å²åŠè ã®äŸãåãäžããŠã STMãSTMLã«ç°¡åã«çœ®ãæããããšãã§ããŸãã
data ForkState = Free | Taken type TFork = TVar ForkState takeFork :: TFork -> STML Bool takeFork tFork = do forkState <- readTVar tFork when (forkState == Free) (writeTVar tFork Taken) pure (forkState == Free)
ç°¡ååå©ïŒ ããããç§ãã¡ãèŠéããããšããããŸãã ããšãã°ã åè©Šè¡ã®èšç®ãäžæããæ¹æ³ã è¿œå ããã®ã¯ç°¡åã§ãïŒ
data STMF next where Retry :: STMF next instance Functor STMF where fmap g Retry = Retry retry :: STML () retry = liftF Retry
ç§ã®ã©ã€ãã©ãªã«ã¯å§ãšããããªéãããããŸãã ç¹ã«ãããã®åè©Šè¡ã¡ãœããã¯Unitãè¿ããŸãããä»»æã®åaãè¿ãå¿ èŠããããŸãã ããã¯åºæ¬çãªå¶éã§ã¯ãªããPoCã®æ¥éãªçºå±ã®ææç©ã§ãããä»åŸä¿®æ£ããŸãã ããã«ããããããããã®ã³ãŒãã§ãããã¢ããèªäœã眮ãæããããšãé€ããŠãå€æŽãªãã§æ®ããŸãã
takeForks :: (TFork, TFork) -> STML () takeForks (tLeftFork, tRightFork) = do leftTaken <- takeFork tLeftFork rightTaken <- takeFork tRightFork when (not leftTaken || not rightTaken) retry
Monadic eDSLã¯åºæ¬å®è£ ã«å¯èœãªéã䌌ãŠããŸãããSTMLã¹ã¯ãªããã®èµ·åã¯ç°ãªããŸãã ç§ã®ã¢ãããã¯ãªã³ã³ãããŒã¿ãŒã¯ãåºæ¬å®è£ ãšã¯ç°ãªããè¿œå ã®åŒæ°ïŒèšç®ãã¹ãã³ããã³ã³ããã¹ãïŒãåããŸãã
atomically :: Context -> STML a -> IO a
ã³ã³ããã¹ãã¯ãŠãŒã¶ãŒããŒã¿ãTVarã®åœ¢åŒã§ä¿åãããããããã€ãã®ç°ãªãã³ã³ããã¹ãã䜿çšã§ããŸãã ããã¯ãããšãã°ããã©ã³ã¶ã¯ã·ã§ã³ã¢ãã«ãåé¢ããå Žåã«åœ¹ç«ã¡ãŸããããã«ãããçžäºã«åœ±é¿ãäžããŸããã ããšãã°ãããã¢ãã«ã§ã¯èšå€§ãªéã®ãŠãŒã¶ãŒããŒã¿ãäœæãããå¥ã®ã¢ãã«ã§ã¯TVarã»ããã¯ãŸã£ããå€æŽãããŸããã 次ã«ãã³ã³ããã¹ããåé¢ããŠã2çªç®ã®ã¢ãã«ããè «ããŠãããé£äººã«èµ·å ããåé¡ãçµéšããªãããã«ããããšã¯çã«ããªã£ãŠããŸãã åºæ¬çãªå®è£ ã§ã¯ãã³ã³ããã¹ãã¯ã°ããŒãã«ã§ããããããã©ã®ããã«åé¿ã§ãããã¯ããããŸããã
å²åŠè ã®èµ·åã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
philosoperWorker :: Context -> Philosopher -> IO () philosoperWorker ctx philosopher = do atomically ctx (changePhilosopherActivity philosopher) threadDelay 5000 philosoperWorker ctx philosopher runPhilosophers :: IO () runPhilosophers = do ctx <- newContext -- . tState1 <- newTVarIO ctx Thinking tState2 <- newTVarIO ctx Thinking tFork1 <- newTVarIO ctx Free tFork2 <- newTVarIO ctx Free forkIO (philosoperWorker ctx (Philosopher tState1 tFork1 tFork2)) forkIO (philosoperWorker ctx (Philosopher tState2 tFork2 tFork1)) threadDelay 100000
解éã«ã€ããŠå°ã
ã¢ãããã¯ã«ã¹ã¯ãªãããå®è¡ãããšã©ããªããŸããïŒ å®éã®ç°å¢ã«å¯Ÿããã·ããªãªã®è§£éãå§ãŸããŸãã ãã®æç¹ã§TVarã®äœæãšå€æŽãéå§ãããå²ã蟌ã¿æ¡ä»¶ããã§ãã¯ããããã©ã³ã¶ã¯ã·ã§ã³ã転éãããã³ã³ããã¹ãã§ã³ããããããããããŒã«ããã¯ãããŠåèµ·åãããã®ãã¢ãããã¯ã§ã ã ã¢ã«ãŽãªãºã ã¯æ¬¡ã®ãšããã§ãã
- äžæã®ãã©ã³ã¶ã¯ã·ã§ã³èå¥åãååŸããŸãã
- çŸåšã®ã³ã³ããã¹ãããããŒã«ã«ã³ããŒãååçã«åé€ããŸãã ããã§çãã³ã³ããã¹ãããã¯ãçºçããŸããããã¯ãéåžžã®ãã¥ãŒããã¯ã¹ã®ããã«åäœããMVarã䜿çšããŠè¡ãããŸãã
- ããŒã«ã«ã³ããŒã䜿çšããŠã¹ã¯ãªããã®è§£éãå®è¡ããçµæãåŸ ã¡ãŸãã
- èšç®ãåéããã³ãã³ããåä¿¡ããå Žåã¯ãã¹ããªãŒã ããã°ããã¹ãªãŒãç¶æ ã«ããŠãæé 1ã«é²ã¿ãŸãã
- çµæãåŸãããããããŒã«ã«ã³ããŒãšã³ã³ããã¹ãã®ç«¶åãã¢ãããã¯ã«ãã§ãã¯ããŸãã
- 競åãèŠã€ãã£ãå Žåã¯ãã¹ããªãŒã ããã°ããã¹ãªãŒãç¶æ ã«ããæé 1ã«é²ã¿ãŸãã
- 競åããªããã°ããã¹ãŠãããŒã«ã«ã³ããŒãã¢ãããã¯ã«ã³ã³ããã¹ãã«åçµããŠããŸãã
- çµããã
ãã®èšç®ãããŒã«ã«ã³ããŒã§äœããããŠããéã«ãã³ã³ããã¹ããå€æŽãããå ŽåããããŸãã ãã®èšç®ã«é¢ä¿ããå°ãªããšã1ã€ã®TVarãå€æŽããããšãã«ã競åãçºçããŸãã ããã¯ãåã€ã³ã¹ã¿ã³ã¹ã«æ ŒçŽãããŠããäžæã®èå¥åã«ãã£ãŠç¢ºèªãããŸãã ãã ããèšç®ã§TVarã䜿çšãããªãã£ãå Žåã競åã¯çºçããŸããã
ç§ãã¡ã®å®éã®ç°å¢ã¯ãç¶æ ãšIOã¢ããã®ã¹ã¿ãã¯ã§ããç¹å®ã®Atomicã¢ããã«ãã£ãŠè¡šçŸãããŸãã ç¶æ ãšããŠ-ãã¹ãŠã®TVarã®ããŒã«ã«ã³ããŒïŒ
data AtomicRuntime = AtomicRuntime { ustamp :: UStamp , localTVars :: TVars } type Atomic a = StateT AtomicRuntime IO a
ãã®ã¢ããå ã§ã¯ãçžäºã«ãã¹ãããã2ã€ã®æ§é ã解ãã解éããŸãã æãåºããšã FreeåãšSTMFåã䜿çšããŠæ§ç¯ãããSTMLåã§ãã Freeã®ã¿ã€ãã¯ãååž°çã§ãããããå°ãé è³ã«ãªããŸãã 圌ã«ã¯2ã€ã®ãªãã·ã§ã³ããããŸãã
data Free fa = Pure a | Free (f (Free fa))
解éã¯åçŽãªãã¿ãŒã³ãããã³ã°ã«ãªããŸãã ã€ã³ã¿ãŒããªã¿ãŒã¯ããã©ã³ã¶ã¯ã·ã§ã³å šäœã®å€ããŸãã¯ãã©ã³ã¶ã¯ã·ã§ã³ãåéããã³ãã³ããè¿ããŸãã
interpretStmf :: STMF a -> Atomic (Either RetryCmd a) interpretStmf (NewTVar a nextF) = Right . nextF <$> newTVar' a interpretStmf (ReadTVar tvar nextF) = Right . nextF <$> readTVar' tvar interpretStmf (WriteTVar tvar a next) = const (Right next) <$> writeTVar' tvar a interpretStmf Retry = pure $ Left RetryCmd interpretStml :: STML a -> Atomic (Either RetryCmd a) interpretStml (Pure a) = pure $ Right a interpretStml (Free f) = do eRes <- interpretStmf f case eRes of Left RetryCmd -> pure $ Left RetryCmd Right res -> interpretStml res runSTML :: STML a -> Atomic (Either RetryCmd a) runSTML = interpretStml
é¢æ°newTVar 'ãreadTVar'ãwriteTvar 'ã¯ããã©ã³ã¶ã¯ã·ã§ã³å€æ°ã®ããŒã«ã«ã³ããŒã§åäœããèªç±ã«å€æŽã§ããŸãã runSTMLåŒã³åºãã¯ãå¥ã®é¢æ°runSTMããäœæãããŸãããã®é¢æ°ã¯ãããŒã«ã«ã§å€æŽãããTVarã®ã³ã³ããã¹ãããã®ã°ããŒãã«ã³ããŒãšã®ç«¶åããã§ãã¯ãããã©ã³ã¶ã¯ã·ã§ã³ãåéãããã©ããã決å®ããŸãã
runSTM :: Int -> Context -> STML a -> IO a runSTM delay ctx stml = do (ustamp, snapshot) <- takeSnapshot ctx (eRes, AtomicRuntime _ stagedTVars) <- runStateT (runSTML stml) (AtomicRuntime ustamp snapshot) case eRes of Left RetryCmd -> runSTM (delay * 2) ctx stml Right res -> do success <- tryCommit ctx ustamp stagedTVars if success then return res else runSTM (delay * 2) ctx stml
ãã®é¢æ°ã¯èª¬æããã«æ®ããŸããtryCommité¢æ°ã®å®è£ æ¹æ³ã«ã€ããŠã¯è©³ãã説æããŸããã æ£çŽèšã£ãŠããŸãæé©ã§ã¯ãããŸããããããã¯å¥ã®èšäºã®ãããã¯ã§ãã
ãããã«
ç§ã®å®è£ ã§ã¯ããŸã æ°ã¥ããªããã°ãªããªã埮åŠãªç¹ãããã€ããããŸãã ãŸã æããã§ãªããã°ãååšããå¯èœæ§ãããããé©åãªåäœã®ããã«ãããå€ãã®ã±ãŒã¹ã確èªããå¿ èŠããããŸãããé©åãªSTMåäœãšèŠãªããããã®ã¯æ確ã§ã¯ãããŸããã ããããå°ãªããšããé£äºãããå²åŠè ã®åé¡ã«ãããå€éšã®éãã¯æããã«ããŸããã§ãããã€ãŸããã¢ã€ãã¢ã¯æ©èœãããããæãèµ·ããããããšãã§ããŸãã ç¹ã«ãã©ã³ã¿ã€ã ãå€§å¹ ã«æé©åãã競åã®è§£æ±ºãšããŒã«ã«ã³ããŒã®åé€ãããã€ã³ããªãžã§ã³ãã«ããããšãã§ããŸãã 解éãšFree Monadã䜿çšããã¢ãããŒãã¯éåžžã«æè»ã§ããããšãããããã³ãŒãã¯ãèªèº«ã§ãããããã«ã¯ããã«å°ãããäžè¬çã«éåžžã«ç°¡åã§ãã ãŸããããã¯ãä»ã®èšèªã§ã®STMã®å®è£ ãžã®éãéããŠãããããåªããŠããŸãã
ããšãã°ãä»ãç§ã¯C ++ã§Free-monadic STMã移æ€ããŠããŸãããããã«ã¯ãã®èšèªã«ç¹æã®ç§èªèº«ã®å°é£ã䌎ããŸãã äœæ¥ã®çµæã«åºã¥ããŠã4æC ++ãã·ã¢2018äŒè°ã§ã¬ããŒããäœæãã誰ããããã蚪åããå Žåã¯ããã®ãããã¯ããã詳现ã«è°è«ã§ããŸãã