使用 TVar 时如何等到 forM_ 完成?
How to wait until forM_ finishes, when using TVar?
我正在编写一个函数,我在其中使用 forM_
处理列表,并将结果附加到 TVar
列表:
import Control.Concurrent.STM
import Control.Concurrent.STM.TVar
import Control.Concurrent (forkIO)
import Control.Monad (forM_)
insert :: a -> [a] -> [a]
insert = (:) -- stub
my_func_c :: (a -> a) -> [a] -> IO [a]
my_func_c my_function arr = do
res_var <- atomically $ newTVar ([]::[a])
forkIO $ forM_ arr $ \x -> atomically $ do
let y = id $! my_function x
modifyTVar res_var (insert y)
atomically $ readTVar res_var
如果我用-threaded
编译,结果总是空的。怎么可能等待线程完成呢?我不能使用 MVar
或 Async
。我必须使用 TVar
或其他基于 TVar
的数据结构来解决这个问题
惯用的解决方案是使用 TMVar
s:
my_func_c :: (a -> a) -> [a] -> IO [a]
my_func_c my_function arr = do
res_var <- atomically $ newTVar []
finished <- atomically $ newEmptyTMVar
forkIO $ do
forM_ arr $ \x -> atomically $ do
let y = id $! my_function x
modifyTVar res_var (insert y)
atomically $ putTMVar finished ()
atomically $ takeTMVar finished >> readTVar res_var
但是如果你真的只允许使用TVar
s,你可以用TVar Bool
模拟TMVar ()
:
my_func_c :: (a -> a) -> [a] -> IO [a]
my_func_c my_function arr = do
res_var <- atomically $ newTVar []
finished <- atomically $ newTVar False
forkIO $ do
forM_ arr $ \x -> atomically $ do
let y = id $! my_function x
modifyTVar res_var (insert y)
atomically $ writeTVar finished True
atomically $ waitTVar finished >> readTVar res_var
waitTVar :: TVar Bool -> STM ()
waitTVar tv = do
finished <- readTVar tv
unless finished retry
在幕后,TMVar a
is just a TVar (Maybe a)
(so TMVar ()
~ TVar (Maybe ())
~ TVar Bool
) with takeTMVar
doing a readTVar
and a retry
,所以上述两个解决方案在操作上是完全等价的。
我正在编写一个函数,我在其中使用 forM_
处理列表,并将结果附加到 TVar
列表:
import Control.Concurrent.STM
import Control.Concurrent.STM.TVar
import Control.Concurrent (forkIO)
import Control.Monad (forM_)
insert :: a -> [a] -> [a]
insert = (:) -- stub
my_func_c :: (a -> a) -> [a] -> IO [a]
my_func_c my_function arr = do
res_var <- atomically $ newTVar ([]::[a])
forkIO $ forM_ arr $ \x -> atomically $ do
let y = id $! my_function x
modifyTVar res_var (insert y)
atomically $ readTVar res_var
如果我用-threaded
编译,结果总是空的。怎么可能等待线程完成呢?我不能使用 MVar
或 Async
。我必须使用 TVar
或其他基于 TVar
惯用的解决方案是使用 TMVar
s:
my_func_c :: (a -> a) -> [a] -> IO [a]
my_func_c my_function arr = do
res_var <- atomically $ newTVar []
finished <- atomically $ newEmptyTMVar
forkIO $ do
forM_ arr $ \x -> atomically $ do
let y = id $! my_function x
modifyTVar res_var (insert y)
atomically $ putTMVar finished ()
atomically $ takeTMVar finished >> readTVar res_var
但是如果你真的只允许使用TVar
s,你可以用TVar Bool
模拟TMVar ()
:
my_func_c :: (a -> a) -> [a] -> IO [a]
my_func_c my_function arr = do
res_var <- atomically $ newTVar []
finished <- atomically $ newTVar False
forkIO $ do
forM_ arr $ \x -> atomically $ do
let y = id $! my_function x
modifyTVar res_var (insert y)
atomically $ writeTVar finished True
atomically $ waitTVar finished >> readTVar res_var
waitTVar :: TVar Bool -> STM ()
waitTVar tv = do
finished <- readTVar tv
unless finished retry
在幕后,TMVar a
is just a TVar (Maybe a)
(so TMVar ()
~ TVar (Maybe ())
~ TVar Bool
) with takeTMVar
doing a readTVar
and a retry
,所以上述两个解决方案在操作上是完全等价的。