【问题标题】:How to exit a forkIO thread when it excutes a loop procedure执行循环过程时如何退出forkIO线程
【发布时间】:2014-09-06 13:44:48
【问题描述】:

我正在写一个音乐播放器之类的东西,但卡在播放进度条上。

在我的程序中,当单击播放按钮时,我使用 forkIO 派生一个控制进度条的线程。但是,分叉的线程现在执行一个循环。当我停止当前歌曲或更改歌曲时,如何通知该线程终止。

我一直在尝试使用IORef Var,例如

flag <- newIORef False

forkIO $ progressBarFunc flag

并在函数progreeBarFunc 中检查标志是否为真并决定是否退出循环。

但这不起作用。

更一般地说,当我使用 forkIO 分叉线程时,如何让分叉线程停止?

另外,如果我有一个 IORef Var 并将其传递给 forkIO 中的函数,主线程和分叉线程是否共享相同的 IORef Var 或分叉线程实际上有它的副本?

【问题讨论】:

    标签: multithreading haskell


    【解决方案1】:

    您可以使用IORefs 在线程之间进行通信。 IORef 在分叉线程中的引用与在主线程中的引用相同。

    您应该检查几件事:

    • 分叉的线程真的有机会测试IORef吗?
    • 您所期望的 UI 交互真的可以从分叉线程中发生吗?许多 UI 库(包括 gtkOpenGL)都对哪些线程可以与 UI 交互有限制。
    • 标志设置的时间是否足够长,以至于分叉的线程有机会看到它?如果标志设置为True,然后在派生线程调用readIORef 之前又回到False,它不会检测到停止。

    解决最后一个问题的一种方法是使用Integer 而不是Bool 作为标志。

    newFlag :: IO (IORef Integer)
    newFlag = newIORef 0
    

    标志的观察者会记住创建观察者时标志的值,并在它变得更大时停止。当线程可以继续时返回True(标志尚未被引发)。

    testFlag :: IORef Integer -> IO (IO Bool)
    testFlag flag = do
        n <- readIORef flag
        return (fmap (<=n) (readIORef flag))
    

    为了提高标志,信号器增加值。

    raiseFlag :: IORef Integer -> IO ()
    raiseFlag ref = atomicModifyIORef ref (\x -> (x+1,()))
    

    这个小示例程序演示了一个IORef 与其他线程共享一个标志。它在给定输入"f" 时分叉新线程,在给定输入"s" 时发出信号停止线程,并在给定输入"q" 时退出。

    main = do
        flag <- newFlag
        let go = do
            command <- getLine
            case command of
                "f" -> do
                    continue <- testFlag flag
                    forkIO $ thread continue
                    go
                "s" -> do
                    raiseFlag flag
                    go
                "q" -> do
                    raiseFlag flag
                    return ()
        go
    

    线程周期性地做一些“工作”,这需要半秒钟,并在继续之前测试继续条件。

    thread :: IO Bool -> IO ()
    thread continue = go
        where
            go = do
                me <- myThreadId
                putStrLn (show me ++ " Outputting")
                threadDelay 500000
                c <- continue
                if c then go else putStrLn (show me ++ " Stopping") >> return ()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-14
      • 2016-05-05
      • 1970-01-01
      • 2013-12-06
      • 1970-01-01
      • 1970-01-01
      • 2016-01-28
      • 1970-01-01
      相关资源
      最近更新 更多