multithreading - Haskell forkIO threads writing on top of each other with putStrLn -
i playing around haskell lightweight threads (forkio
) following code:
import control.concurrent begintest :: io () begintest = go go = putstrln "very interesting string" go return () main = 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"
now expected output whole bunch of these:
very interesting string interesting string interesting string interesting string
with 1 of these somewhere in there:
main thread
however, output (or first several lines anyway) turned out this:
very interesting string interesting string interesting string interesting string interesting string interesting string interesting string interesting string interesting string interesting string interesting string interesting string interesting string interesting string interesting string interesting string interesting string interesting string interesting string 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
every few lines text shift, though it's pretty clear very interesting string
s ended on top of each other, because somehow threads using putstrln
@ same time ended writing stdout on top of each other. why this, , how (without resorting message passing, timing, or other overcomplicated , convoluted solution) can overcome?
simply put, putstrln
not atomic operation. every character may interleaved other different thread.
(i not sure whether in multi-byte encodings such utf8 guaranteed multi-byte character atomically handled.)
if want atomicity, can use shared mutex e.g.
do lock <- newmvar () let atomicputstrln str = takemvar lock >> putstrln str >> putmvar lock () forkio $ forever (atomicputstrln "hello") forkio $ forever (atomicputstrln "world")
as suggested in comments below, can simplify , make above exception-safe follows:
do lock <- newmvar () let atomicputstrln str = withmvar lock (\_ -> putstrln str) forkio $ forever (atomicputstrln "hello") forkio $ forever (atomicputstrln "world")
Comments
Post a Comment