我正在编写类似音乐播放器的内容,并且无法使用播放进度条。
在我的程序中单击播放按钮时,我使用forkIO来分叉控制进度条的线程。但是,分叉线程现在执行循环。当我停止当前歌曲或更改歌曲时,如何通知该线程终止。
我一直在尝试使用IORef Var,例如
flag <- newIORef False
forkIO $ progressBarFunc flag
并在函数progreeBarFunc
中检查flag是否为true并决定是否退出循环。
但这不起作用。
更一般地说,当我使用forkIO来分叉线程时,如何告诉分叉线程停止?
另外,如果我有一个IORef Var并将它传递给forkIO中的函数,那么主线程和分叉线程是否共享相同的IORef Var,或者分叉线程实际上有它的副本?
答案 0 :(得分:3)
您可以使用IORef
在线程之间进行通信。 IORef
在分叉线程中引用与在主线程中相同的内容。
您应该检查一些事项:
IORef
?gtk
和OpenGL
)都限制哪些线程可以与UI交互。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
线程会定期执行一些工作&#34;这需要半秒钟,并在继续之前测试继续条件。
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 ()