如何将System.IO.Unsafe与TVars一起使用?

时间:2012-02-22 22:20:42

标签: haskell

我想在STM事务中调用UDP发送函数,这样我就可以避免在最终发送值之前读取m'(并且可以由其他线程更新)的代码如下所示。连续两个条款让我看起来很“无助”。

sendRecv s newmsgs q m = do
     m' <- atomically $ readTVar m
     time <- getPOSIXTime
     result <- appendMsg newmsgs key m
     when (result > 0) (atomically $ do 
                           mT <- readTVar m
                           qT <- readTVar q
                           --let Just messages = Map.lookup key mT in sendq s (B.pack $ unwords messages) "192.168.1.1" 4711 
                           let mT' = Map.delete key mT
                               qT' = PSQ.delete key qT
                           writeTVar q (PSQ.insert key time qT')
                           writeTVar m (Map.insert key [newmsgs] mT'))
     when (result > 0) (let Just messages = Map.lookup key m' in sendq s (B.pack $ unwords messages) "192.168.1.1" 4711) 

sendq :: Socket -> B.ByteString -> String -> PortNumber -> IO ()
sendq s datastring host port = do
      hostAddr <- inet_addr host
      sendAllTo s datastring (SockAddrInet port hostAddr)
      return ()

我认为通过使用newTVarIO并使用import System.IO.Unsafe调用电视广告,我最终可以在某处使用unsafePerformIO并在事务中调用我的sendq函数(返回IO()

但是,我找不到这个“某处”的位置?是在TVar的创作?是代替atomically $ do吗?我是否理解unsafePerformIO的适用性错误?

2 个答案:

答案 0 :(得分:8)

无法从STM块内部执行IO,因为无法撤消常规IO。如果要执行某些IO,则必须在STM块中安排它,但在外部执行。例如:

foo tvar = do
    scheduledAction <- atomically $ do
        v <- readTVar tvar
        when v retry
        return (sendSomethingOnASocket "okay, we're done here")
    scheduledAction

答案 1 :(得分:4)

如果确实需要在事务中执行IO,那么unsafeIOToSTM :: IO a -> STM a,但是您应该首先阅读文档,因为有几个需要注意的问题。特别是,如果必须重试事务,则可以多次运行IO操作。

那就是说,在这种情况下,我认为这不合适,你应该重构你的代码,以便在事务之外发送消息。