2

我正在使用 Pipes.Concurrent 用 GTK 编写一个简短的 GUI 程序。这是一个扫雷游戏,所以我正在构建一个按钮网格。

我构建并连接我的按钮:

b <- buttonNewWithLabel (show $ adjacencies board ! i)
on b buttonActivated 
     $ void . atomically $ send output (ClickSignal i (mines board ! i))
return b

我将管道连接到:

(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

几乎按预期运行。但是如果我点击按钮 1,什么都不会发生。但是如果我按下按钮 23,它会将信息标签更新为“1..”。如果我单击另一个按钮,它将更新为“23..”,依此类推。

我怀疑要么我无法理解并发管道是如何在某个级别上工作的,要么是惰性 IO 正在做一些奇怪的事情。

4

1 回答 1

3

Using the latest buffering strategy means there's always a value available to read in the buffer, so await will always return immediately; and send will likewise always succeed, so long as it gets a chance to run. A test program I wrote worked okay in ghci, but when compiled it never let the thread run that was trying to read from the console and send; I just got an endless stream of 0 until I terminated the program.

Your consumer run doesn't have anything in it that would cause it to pause, so it may similarly be starving the thread that is trying to send to output. If this is the case, a small threadDelay 100 or so before each call to run might help.

Another possibility, and a more efficient one, would be to use a buffer that blocks the Consumer until there's a message to act on. To avoid blocking the event callback, you could use the newest 1 buffer strategy, which would always succeed with send and overwrite the current value if there was already one there.

If neither of those help, then I suspect that there's something else going on with the way the GUI framework you're using is plumbed, but I am not very familiar with the GTK bindings in Haskell so I can't be of much help with that.

于 2016-02-03T06:25:58.717 回答