如何将System.IO.Unsafe与TVars一起使用?
问题描述:
我想在STM事务中调用一个UDP发送函数,这样我就可以避免在最终发送值之前避免m'被读取(并且可以由其他线程更新)的代码,如下所示:&其中两个连续的where子句让我看起来很“无奈”。如何将System.IO.Unsafe与TVars一起使用?
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
调用TVars和使用import System.IO.Unsafe
我可能最终使用unsafePerformIO
的地方,并从交易中调用我的SendQ函数(即返回IO()
)。
但是,我不知道这个“某处”在哪里?它是在创建TVar吗?是不是atomically $ do
?我是否理解unsafePerformIO的适用性错误?
答
IO不能从STM块内完成,因为通用IO不能被撤消。如果你想做一些IO,你必须在STM块中安排它,但是在外面做。例如:
foo tvar = do
scheduledAction <- atomically $ do
v <- readTVar tvar
when v retry
return (sendSomethingOnASocket "okay, we're done here")
scheduledAction
答
如果你真的需要的事务中做IO,有unsafeIOToSTM :: IO a -> STM a
,但是你要确保先阅读文档,因为有几个陷阱,以做到心中有数。特别是,如果事务必须重试,IO操作可能会运行多次。
也就是说,我认为在这种情况下这不合适,而且您应该重构代码,以便将消息发送到事务之外。
+1指出这真的不可能。 – 2012-02-22 22:28:28
有没有可能将线程a的事务优先于线程b?例如。如果线程a不断地处理事务并且更频繁地使用线程b,那么可能会有什么“中断”吗?我尝试了一个MVar,其中b可以防止一段时间的运行。但不是很优雅。 – 2012-02-22 23:38:26
@JFritsch MVars和STM并没有真正的混合。我不知道有什么办法可以要求一个线程优先于另一个线程。但是,如果你不活跃,两条线索最终都会取得进展。 – 2012-02-22 23:44:50