gpt4 book ai didi

multithreading - Haskell forkIO 线程使用 putStrLn 在彼此之上写入

转载 作者:行者123 更新时间:2023-12-04 15:20:53 24 4
gpt4 key购买 nike

我正在使用 Haskell 轻量级线程 ( forkIO ) 使用以下代码:

import Control.Concurrent

beginTest :: IO ()
beginTest = go
where
go = do
putStrLn "Very interesting string"
go
return ()

main = do
threadID1 <- forkIO $ beginTest
threadID2 <- forkIO $ beginTest
threadID3 <- forkIO $ beginTest
threadID4 <- forkIO $ beginTest
threadID5 <- forkIO $ beginTest

let tID1 = show threadID1
let tID2 = show threadID2
let tID3 = show threadID3
let tID4 = show threadID4
let tID5 = show threadID5

putStrLn "Main Thread"
putStrLn $ tID1 ++ ", " ++ tID2 ++ ", " ++ tID3 ++ ", " ++ tID4 ++ ", " ++ tID5
getLine
putStrLn "Done"

现在,对此的预期输出将是一大堆:
Very interesting string
Very interesting string
Very interesting string
Very interesting string

其中一个在那里的某个地方:
Main Thread

然而,输出(或前几行)结果是这样的:
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very VVVViMeeeenarrrrtiyyyyen r iiiieTnnnnshtttttreeeeierrrrnaeeeegdssss
ttttsiiiitTnnnnrhggggir nessssgatttt
drrrrIiiiiVdnnnne ggggr5



y1 ,VVVVi eeeenTrrrrthyyyyer reiiiieannnnsdtttttIeeeeidrrrrn eeeeg5ssss 2tttts,iiiit nnnnrTggggih nrssssgetttt
arrrrdiiiiVInnnnedggggr



y5 3VVVVi,eeeen rrrrtTyyyyeh rriiiieennnnsatttttdeeeeiIrrrrndeeeeg ssss 5tttts4iiiit,nnnnr ggggiT nhssssgrtttt
errrraiiiiVdnnnneIggggrd



y 5VVVVi5eeeen
rrrrtyyyye riiiiennnnsttttteeeeirrrrneeeegssss ttttsiiiitnnnnrggggi nssssgtttt
rrrriiiiVnnnneggggr



y VVVVieeeenrrrrtyyyye riiiiennnnsttttteeeeirrrrneeeegssss ttttsiiiitnnnnrggggi nssssgtttt
rrrriiiiVnnnneggggr

文本每隔几行就会移动一次,但很明显 Very interesting string s 最终彼此重叠,因为不知何故线程使用 putStrLn同时最终在彼此之上写入标准输出。为什么会这样,以及如何(不求助于消息传递、计时或其他一些过于复杂和令人费解的解决方案)可以克服它?

最佳答案

简单地说,putStrLn不是原子操作。每个字符都可以与来自不同线程的任何其他字符交错。

(我也不确定在多字节编码(如 UTF8)中是否保证多字节字符是原子处理的。)

如果你想要原子性,你可以使用共享互斥锁,例如

do lock <- newMVar ()
let atomicPutStrLn str = takeMVar lock >> putStrLn str >> putMVar lock ()
forkIO $ forever (atomicPutStrLn "hello")
forkIO $ forever (atomicPutStrLn "world")

正如以下评论中所建议的,我们还可以简化上述异常并使其安全,如下所示:
do lock <- newMVar ()
let atomicPutStrLn str = withMVar lock (\_ -> putStrLn str)
forkIO $ forever (atomicPutStrLn "hello")
forkIO $ forever (atomicPutStrLn "world")

关于multithreading - Haskell forkIO 线程使用 putStrLn 在彼此之上写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32040536/

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