Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 多线程和gtk2hs_Multithreading_Haskell_Gtk_Reactive Banana - Fatal编程技术网

Multithreading 多线程和gtk2hs

Multithreading 多线程和gtk2hs,multithreading,haskell,gtk,reactive-banana,Multithreading,Haskell,Gtk,Reactive Banana,我正在用反应式香蕉和gtk2hs编写一些代码,这些代码需要从文件句柄读取。我需要至少有两个线程(一个用于读取带有响应香蕉的键盘事件,另一个用于读取文件句柄),因此目前我有如下代码: type EventSource a = (AddHandler a, a -> IO ()) fire :: EventSource a -> a -> IO () fire = snd watch :: EventSource ByteString -> Handle -> IO

我正在用反应式香蕉和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
程序在到达
mainAxn
的末尾时立即返回。我尝试使用以下方法解决此问题:

forkIO mainGUI 
forever $ return ()
但是GTKGUI从来没有打开过,我不明白为什么


正确的方法是什么?我遗漏了什么?

这里的基本问题是,在Haskell中,
main
一退出,整个程序就被拆除。解决方法就是保持
main
线程打开;e、 g

done <- newEmptyMVar
forkOS (mainGUI >> putMVar done ())
takeMVar done
done>putMVar-done())
takeMVar完成

我还将
forkIO
替换为
forkOS
。GTK在Windows上使用(OS-)线程本地状态,因此作为一种防御编程,最好确保
mainGUI
在绑定线程上运行,以防有一天您想要支持Windows。

Daniel Wagner回答了我的问题,但我从#haskell IRC频道得到了更多信息,我将在这里发布,以供将来参考

更好的解决方案是让主线程成为GUI线程,并在一个新的线程中处理反应性香蕉事件网络,而不是跳过分叉GUI线程和让主线程进入睡眠的尴尬循环。我最终修改了我的
main
函数以包含以下内容:

keyChan <- newChan
_ <- forkIO $ watchKeys keyPress keyChan
_ <- win `on` keyPressEvent $
    eventKeyVal >>= liftIO . writeChan keyChan >> return True
现在我可以在一个地方处理
postGUI(A)Sync
问题,方法是定义:

reactimateSafe :: Frameworks t => Event t (IO ()) -> Moment t ()
reactimateSafe = reactimate . fmap postGUIAsync

对于任何修改GTK对象的IO操作,使用
reactimateSafe
forever$return()
都是一个坏主意——而是等待
mainGUI
线程完成。e、 g.此外,您应该使用
forkOS mainGUI
。请看原因。(这里是反应性香蕉的作者。)我认为这个问题与反应性香蕉无关。在我看来,您需要
-threaded
,以便
threadWaitRead
与GTK GUI同时运行;但不完全确定。@HeinrichApfelmus是的,它非常独立于反应性香蕉,我只是加入了这些信息来更好地解释我的用例。另外,这是你亲自回答的第二个问题——谢谢你这么积极!
keyChan <- newChan
_ <- forkIO $ watchKeys keyPress keyChan
_ <- win `on` keyPressEvent $
    eventKeyVal >>= liftIO . writeChan keyChan >> return True
watchKeys :: EventSource KeyVal -> Chan KeyVal -> IO ()
watchKeys keyPress chan = forever $
    readChan chan >>= fire keyPress 
reactimateSafe :: Frameworks t => Event t (IO ()) -> Moment t ()
reactimateSafe = reactimate . fmap postGUIAsync