2012-02-22 14 views
3

STMトランザクション内でUDP send関数を呼び出して、値が最終的に送信される前にm 'が読み取られ、他のスレッドによって更新される可能性のあるコードを避けることができます。& where where where where clauses私をかなり無力に見せてください。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を使用することができ、トランザクション内から(IO()を返します)私のSENDQ関数を呼び出すと思いました。

しかし、この「どこか」がどこにあるのかわかりません。それはTVarの創作時ですか?それはatomically $ doの代わりですか? unsafePerformIOの適用性が間違っているという意味を理解していますか?

答えて

8

一般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 
+0

+1これは実際には不可能であることを指摘しています。 –

+0

スレッドbのスレッドaのトランザクションに優先順位を付ける可能性はありますか?例えば。スレッドaが常にトランザクションとスレッドbをより頻繁に持っていない場合、bの「割り込み」を行うことができますか?私はMVarを試して、bがしばらく実行されないようにすることができました。しかしエレガントではなかった。 –

+0

@JFritsch MVarsとSTMは実際には混在しません。あるスレッドが別のスレッドよりも優先順位を付けるように求める方法はわかりません。しかし、ライブロックしていない場合、両方のスレッドが最終的に進歩するはずです。 –

4

トランザクション内でIOを行うには、あなた本当に必要がある場合は、unsafeIOToSTM :: IO a -> STM aがあります、しかし、あなたは注意すべきいくつかの落とし穴があるので、最初のドキュメントを読んで確認してください。特に、トランザクションが再試行される必要がある場合、IOアクションは複数回実行される可能性があります。

これは、このケースでは適切ではないと思われます。メッセージがトランザクション外に送信されるように、コードをリファクタリングする必要があります。

関連する問題