Я пишу код с реактивным бананом и gtk2hs, который нужно читать из дескриптора файла. Мне нужно иметь как минимум два потока (один для чтения событий клавиатуры с реактивным бананом и один для чтения из дескриптора файла), поэтому на данный момент у меня есть код, который выглядит примерно так:
type EventSource a = (AddHandler a, a -> IO ())
fire :: EventSource a -> a -> IO ()
fire = snd
watch :: EventSource ByteString -> Handle -> IO ()
watch textIn pty = forever $
hGetLine pty >>= fire textIn >> threadWaitRead pty
Со следующей основной функцией:
mainAxn :: IO ()
mainAxn = do
h <- openFile "foo" ReadMode
initGUI
win <- windowNew
txt <- textViewNew
containerAdd win txt
widgetShowAll win
(keyPress, textIn) <-
(,) <$> newAddHandler <*> newAddHandler
network <- setupNetwork keyPress textIn
actuate network
_ <- forkIO $ watch textIn h
_ <- win `on` keyPressEvent $
eventKeyVal >>= liftIO . fire keyPress >> return True
mainGUI
и моя сеть событий настроена следующим образом:
setupNetwork :: EventSource KeyVal -> EventSource ByteString -> IO EventNetwork
setupNetwork keyPress textIn = compile $ do
ePressed <- fromAddHandler $ addHandler keyPress
eText <- fromAddHandler $ addHandler textIn
reactimate $ print <$> (filterJust $ keyToChar <$> ePressed)
reactimate $ print <$> eText
(за исключением моего фактического кода, эти вызовы reactimate
записываются в TextView
, встроенный в mainAxn
). Я обнаружил, что мне нужно построить с -threaded
, чтобы сеть событий правильно захватила как текст из textIn
, так и нажатия клавиш из keyPress
, что вызвало проблемы, потому что небезопасно одновременно изменять объекты из пакета gtk.
На данный момент у меня есть postGUIAsync
вызовов, разбросанных по всему моему коду, и я обнаружил, что использование postGUISync
приводит к взаимоблокировке всего этого --- я не уверен, почему. Я думаю, это потому, что я вызываю postGUISync
внутри того же потока, что и mainGUI
.
Кажется, было бы лучше запускать весь материал GUI в своем собственном потоке и использовать функции postGUI*
для каждого доступа к нему. Однако, когда я изменяю последнюю строку mainAxn
на
forkIO mainGUI
return ()
программа немедленно возвращается, когда достигает конца mainAxn
. Я попытался исправить это, используя:
forkIO mainGUI
forever $ return ()
но тогда графический интерфейс gtk вообще никогда не открывается, и я не понимаю, почему.
Как правильно это сделать? Что мне не хватает?
forever $ return ()
— плохая идея — вместо этого дождитесь завершения потокаmainGUI
. например hackage.haskell.org/package/threads- 0.5.1.3/документы/ - person chi   schedule 09.06.2015forkOS mainGUI
. См. мое обсуждение многопоточности в gtk2hs, чтобы понять почему. - person Daniel Wagner   schedule 09.06.2015-threaded
для того, чтобыthreadWaitRead
запускался одновременно с графическим интерфейсом GTK; хотя не совсем уверен. - person Heinrich Apfelmus   schedule 10.06.2015