Multithreading 使用TChan的管道式操作
我想在两个线程之间实现一个管道。我有一个线程A,它接收数据,处理数据,并将其发送给线程B。我有一个MVar,它检查数据是否被完全处理 但是,我遇到了一个异常Multithreading 使用TChan的管道式操作,multithreading,haskell,stm,Multithreading,Haskell,Stm,我想在两个线程之间实现一个管道。我有一个线程A,它接收数据,处理数据,并将其发送给线程B。我有一个MVar,它检查数据是否被完全处理 但是,我遇到了一个异常***异常:STM事务中的线程被无限期阻塞 为什么我的线程被阻塞?我认为当第一个线程在通道上写入数据时,第二个线程可以读取数据 fstPipe :: (a -> b) -> TChan b -> MVar () -> [a] -> IO () fstPipe f chIn m xs = do ( mapM
***异常:STM事务中的线程被无限期阻塞
为什么我的线程被阻塞?我认为当第一个线程在通道上写入数据时,第二个线程可以读取数据
fstPipe :: (a -> b) -> TChan b -> MVar () -> [a] -> IO ()
fstPipe f chIn m xs = do
( mapM_(\x-> atomically $ writeTChan chIn $ f x) xs) >> putMVar m ()
pipelineDone channel mIn = do
isDone <- fmap isJust $ tryTakeMVar mIn
isEmpty <- atomically $ isEmptyTChan channel
return $ isDone && isEmpty
lastPipe f chIn mIn = iter
where iter = do
atomically $ fmap f $ readTChan chIn
isDone <- pipelineDone chIn mIn
unless isDone $ iter
pipeline = do
chIn <- atomically newTChan
m <- newEmptyMVar
first <- async $ fstPipe reverse chIn m $ replicate 10 [1..500]
last <- async $ lastPipe print chIn m
wait first
wait last
fstPipe::(a->b)->TChan b->MVar()->[a]->IO()
fstPipe f chIn m xs=do
(mapM(\x->atomically$writeTChan-chIn$fx)xs)>>putMVar m()
pipelineDone通道最小值=do
isDone我认为这是一种竞赛条件:
- 在
putMVar
- 前进
lastPipe
阅读所有内容,然后调用pipelineDone
pipelineDone
返回False
,因为putMVar
尚未完成
lastPipe
将尝试从频道读取
putMVar
执行,但为时已晚
现在,lastPipe
卡在一个空通道上读取。在同一代码块中使用STM和信号量对我来说似乎很奇怪。。。为什么不在STM中完成整个过程
特别是,为什么不使用一个TChan(可能是x)
,而Nothing
表示序列的结束
另外,请注意,您的fstPipe
可能只是生成了一堆未经计算的thunk,并立即将它们放入TChan
,而没有实际计算任何内容。您可能需要一个seq
或类似的命令来强制在该线程上执行一些实际工作。您的问题在于管道完成的逻辑。目前,您有:
pipelineDone channel mIn = do
isDone <- fmap isJust $ tryTakeMVar mIn
isEmpty <- atomically $ isEmptyTChan channel
return $ isDone && isEmpty
这将只是轮询MVar,而不是实际清空它。谢谢!因此,如果我理解得很好,如果我写“writechan chin$seq$fx”,它将计算fx,然后将其添加到频道?如果你写writechan ch$!fx
(注意$!
而不是$
),这将强制f
的结果为弱头范式。如果你想进一步评估。。。这是另一个问题。搜索以前的答案。;-)
pipelineDone channel mIn = do
stillRunning <- isEmptyMVar mIn
isEmpty <- atomically $ isEmptyTChan channel
return $ (not stillRunning) && isEmpty