I'm using Pipes.Concurrent to write a short GUI program with GTK. It's a minesweeper-esque game, so I'm constructing a grid of buttons.
I construct and connect my buttons with:
b <- buttonNewWithLabel (show $ adjacencies board ! i)
on b buttonActivated
$ void . atomically $ send output (ClickSignal i (mines board ! i))
return b
And I connect the pipe with:
(output, input) <- spawn (latest (ClickSignal 0 False))
let run = do
sig <- await
case sig of
ClickSignal i isMine ->
if isMine
then do
lift $ labelSetText info (show i ++ " -- LOSE!")
else do
lift $ labelSetText info (show i ++ " -- Ok")
run
Empty -> do
lift $ labelSetText info "Empty Case"
run
void . forkIO $ do
runEffect $ fromInput input >-> run
performGC
It runs almost as expected. But if I click on button 1, nothing happens. But if I press button 23, it will update the info label to "1..". If I click on another button, it will update to "23..", and so forth.
I suspect that either I'm failing to understand how concurrent pipes are meant to work on some level or lazy IO is doing something weird.
答案 0 :(得分:3)
使用latest
缓冲策略意味着缓冲区中总有一个值可供读取,因此await
将始终立即返回;只要它有机会跑,send
同样总能成功。我写的测试程序在ghci中运行正常,但是在编译时它永远不会让试图从控制台和send
读取的线程运行;我得到了无穷无尽的0
,直到我终止了该计划。
您的消费者run
中没有任何会导致其暂停的内容,因此可能同样会使正在尝试send
到output
的线程挨饿。如果是这种情况,在每次调用threadDelay 100
之前,run
左右可能会有所帮助。
另一种可能性和更有效的方法是使用阻塞Consumer
的缓冲区,直到有消息要作用。为了避免阻塞事件回调,您可以使用newest 1
缓冲区策略,该策略始终与send
成功,并覆盖当前值(如果已存在)。
如果这两者都没有帮助,那么我怀疑你正在使用的GUI框架的方式还有其他问题,但我不熟悉Haskell中的GTK绑定,所以我不能对此有很大帮助。