gpt4 book ai didi

multithreading - 在执行循环过程时如何退出fork IN线程

转载 作者:行者123 更新时间:2023-12-03 12:55:48 27 4
gpt4 key购买 nike

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

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

例如,我一直在尝试使用IORef Var
flag <- newIORef FalseforkIO $ progressBarFunc flag
然后在progreeBarFunc函数中检查flag是否为true并决定退出循环。

但这是行不通的。

更笼统地说,当我使用forkIO派生线程时,如何告诉派生线程停止?

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

最佳答案

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

您应该检查以下几件事:

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

  • 解决最终问题的一种方法是使用 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 ()

    关于multithreading - 在执行循环过程时如何退出fork IN线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25696510/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com