GI-Gtk回调线程

时间:2017-08-06 21:12:31

标签: multithreading haskell gtk

在GI-Gtk中使用回调时遇到线程问题。请考虑以下程序:

import GI.Gtk hiding (main)
import GI.Gdk
import GI.GLib
import GI.GLib.Constants

import qualified GI.Gtk as Gtk 

import Control.Concurrent
import Control.Concurrent.MVar

main = do
    t <- myThreadId
    putStrLn $ "init "++show t

    Gtk.init Nothing

    d <- dialogNew
    dialogRun d
    onWidgetDestroy d onDestroy

    Gtk.main

onDestroy :: IO ()
onDestroy = do
    t <- myThreadId
    putStrLn $ "onDestroy "++show t
    runOnGUI $ putStrLn "Destroying"
    putStrLn "Destroyed"
    Gtk.mainQuit

runOnGUI :: IO a -> IO a
runOnGUI action = do
    ans <- newEmptyMVar
    threadsAddIdle PRIORITY_DEFAULT_IDLE $ action >>= putMVar ans >> return False
    takeMVar ans

运行上述程序时,程序在我尝试关闭窗口时挂起,并得到以下输出:

init ThreadId 11
Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged.
onDestroy ThreadId 12

单独查看代码,如果从主线程调用runOnGUI(我希望它是这样),我希望看到这个死锁。但是根据输出,应该在不同的线程上调用runOnGUI,从而避免死锁。

在我的实际程序中,我试图通过在if currentThread /= mainThread类型条件中保护runOnGUI来避免这种类型的死锁;但是,正如上面的例子所示,这似乎不够。

0 个答案:

没有答案