Em Programação Paralela e Concorrente em Haskell , de Simon Marlow, o capítulo 7 começa na página 125 com este exemplo,
import Control.Concurrent
import Control.Monad
import System.IO
main :: IO ()
main = do
hSetBuffering stdout NoBuffering
_ <- forkIO (replicateM_ 100000 (putChar 'A'))
replicateM_ 100000 (putChar 'B')
que tem uma saída como esta
BBBBBBBABABABAAAAAAA
(que, aliás, é o resultado que realmente obtive ao alterar 100000
para 10
o snippet acima e executar o programa).
No final do capítulo, página 140, é feito o seguinte comentário (grifo meu):
[…] Este é um exemplo da garantia de imparcialidade na prática. […]. Portanto, isso leva à alternância perfeita entre as duas threads. A única maneira de o padrão de alternância ser quebrado é se uma thread for desescalonada enquanto não estiver segurando o
MVar
. De fato, isso acontece de tempos em tempos como resultado da preempção, e ocasionalmente vemos uma longa sequência de uma única letra na saída.
Com base no resultado que mostrei, sim, consigo ver que a alternância está quebrada, mas não entendi bem a explicação acima. Não há nem um MVar
no primeiro exemplo.
O mesmo parágrafo que você está citando também inclui
É aí que está o MVar: é
stdout
. Você pode consultar a fonte do Handle para confirmar:Quanto a como você poderia não obter saídas perfeitamente intercaladas se uma das threads fosse preemptada, é difícil saber o que eu poderia dizer que não esteja já no capítulo que você está lendo. A thread preemptada para de imprimir por um tempo, pois é desescalonada sem manter nenhum bloqueio. Até que seja escalonada novamente, a outra thread pode escrever livremente.