如何在Haskell中强制主线程等待其所有子线程完成 [英] How to force main thread to wait for all its child threads finish in Haskell

查看:92
本文介绍了如何在Haskell中强制主线程等待其所有子线程完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的Haskell代码中,如何强制主线程等待直到其所有子线程完成.

In the following Haskell code, how to force main thread to wait till all its child threads finish.

在此链接的终止程序"部分中,我无法使用forkFinally:(

I could not able to use forkFinally as given in the section "Terminating the Program" here in this link: (http://hackage.haskell.org/package/base-4.7.0.2/docs/Control-Concurrent.html).

使用TMVar时,我得到了期望的结果.但是我想和TVar一起做. 请帮忙.

I get desired result when using TMVar. But I want to do this with TVar. Please help.

module Main
where
import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM

type TInt = TVar Int

transTest :: TInt -> Int -> IO ()
transTest n t = do 
    atomically $ do 
        t1 <- readTVar n                    
        doSomeJob t
        t2 <- readTVar n
        writeTVar n t

doSomeJob :: Int -> STM ()
doSomeJob t = do
    x <- newTVar 0
    let l = 10^6*t
    forM_ [1..l] (\i -> do 
        writeTVar x i )            

main :: IO ()
main = do
    n <- newTVarIO 0

    let v = 5
    forkIO (transTest n v)

    let v = 3
    forkIO (transTest n v)

    let v = 7
    forkIO (transTest n v)

    let v = 1
    forkIO (transTest n v)  


    r <- atomically $ readTVar n
    putStrLn("Last updated value = " ++ (show r))

推荐答案

我过去所做的是为每个分支的线程创建一个MVar,然后使用forkFinally分叉这些线程,以便最后,每个线程都会在MVar中放入一个虚拟值(即,我将MVar用作同步原语).然后,我可以在这些MVar上调用takeMVar来等待.

What I did in the past was to create a little MVar for each forked thread and then use forkFinally to fork the threads such that at the very end, each thread would put a dummy value into the MVar (i.e. I used the MVar as a synchronisation primitive). I could then call takeMVar on those MVars to wait.

我将其包装到一个小辅助函数中:

I wrapped it into a little helper function:

forkThread :: IO () -> IO (MVar ())
forkThread proc = do
    handle <- newEmptyMVar
    _ <- forkFinally proc (\_ -> putMVar handle ())
    return handle

使用此代码,您的代码可以更改为类似的

Using this, your code could be changed to something like

-- Fork four threads
threads <- forM [5, 3, 7, 1] (\v -> forkThread (transTest n v))

-- Wait for all of them
mapM_ takeMVar threads

但是,那是在我读了西蒙·马洛(Simon Marlow)的(最出色的)《并行和并行编程在Haskell》一书之前,这使我意识到了

However, that was before I read the (most excellent) book "Parallel and Concurrent Programming in Haskell" by Simon Marlow, which made me aware of the async package. The package provides an abstraction which not only takes care of all these things, so you can write just

-- Runs 'transTest n {5,3,7,1}' in parallel and waits for all threads
_ <- mapConcurrently (transTest n) [5, 3, 7, 1]

...它还处理诸如(异步)异常之类的事情.

...it also takes care of things such as (asynchronous) exceptions.

这篇关于如何在Haskell中强制主线程等待其所有子线程完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆