
On Tue, Jul 26, 2011 at 1:25 AM, Edward Z. Yang
Hello Brandon,
The answer is subtle, and has to do with what references are kept in code, which make an object considered reachable. Essentially, the main thread itself keeps the MVar live while it still has forking to do, so that it cannot get garbage collected and trigger these errors.
Ah, okay. That seems like an obvious explanation for the exceptions to be raised at the same time in the forked threads.
Here is a simple demonstrative program:
main = do lock <- newMVar () forkIO (takeMVar lock) forkIO (takeMVar lock) forkIO (takeMVar lock)
(snip)
But in the meantime (esp. between invocation 2 and 3), the MVar cannot be garbage collected, because it is live on the stack.
Could GHC have been more clever in this case? Not in general, since deciding whether or not a reference will actually be used or not boils down to the halting problem.
loop = threadDelay 100 >> loop -- prevent blackholing from discovering this main = do lock <- newEmptyMVar t1 <- newEmptyMVar forkIO (takeMVar lock >> putMVar t1 ()) forkIO (loop `finally` putMVar lock ()) takeMVar t1
Maybe we could do something where MVar references are known to be writer ends or read ends, and let the garbage collector know that an MVar with only read ends left is a deadlocked one. However, this would be a very imprecise analysis, and would not help in your original code (since all of your remaining threads had the possibility of writing to the MVar: it doesn't become clear that they can't until they all hit their takeMVar statements.)
I think this is the crux of what I was confused about. I had assumed read vs. write was being taken into account by the runtime in raising BlockedIndefinitelyOnMVar. This makes it obvious: loop = threadDelay 100 >> loop -- prevent blackholing from discovering this main = do lock <- newEmptyMVar forkIO (loop `finally` takeMVar lock) takeMVar lock Given that, I still can't say I understand what is happening in my original code. I'll try to work out an even simpler example on my own. Thanks for the thoughtful response, Brandon
Cheers, Edward