<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 30 January 2017 at 16:18, David Feuer <span dir="ltr"><<a href="mailto:david@well-typed.com" target="_blank">david@well-typed.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I forgot to CC ghc-devs the first time, so here's another copy.<br>
<div class="gmail-HOEnZb"><div class="gmail-h5"><br>
I was working on #11760 this weekend, which has to do with concurrency<br>
breaking lazy ST. I came up with what I thought was a pretty decent solution (<br>
<a href="https://phabricator.haskell.org/D3038" rel="noreferrer" target="_blank">https://phabricator.haskell.<wbr>org/D3038</a> ). Simon Peyton Jones, however, is quite<br>
unhappy about the idea of sticking this weird unsafePerformIO-like code<br>
(noDup, which I originally implemented as (unsafePerformIO . evaluate), but<br>
which he finds ugly regardless of the details) into fmap and (>>=).  He's also<br>
concerned that the noDuplicate# applications will kill performance in the<br>
multi-threaded case, and suggests he would rather leave lazy ST broken, or<br>
even remove it altogether, than use a fix that will make it slow sometimes,<br>
particularly since there haven't been a lot of reports of problems in the<br>
wild.<br></div></div></blockquote><div><br></div><div>In a nutshell, I think we have to fix this despite the cost - the implementation is incorrect and unsafe.</div><div><br></div><div>Unfortunately the mechanisms we have right now to fix it aren't ideal - noDuplicate# is a bigger hammer than we need.  All we really need is some way to make a thunk atomic, it would require some special entry code to the thunk which did atomic eager-blackholing.  Hmm, now that I think about it, perhaps we could just have a flag, -fatomic-eager-blackholing.  We already do this for CAFs, incidentally. The idea is to compare-and-swap the blackhole info pointer into the thunk, and if we didn't win the race, just re-enter the thunk (which is now a blackhole).  We already have the cmpxchg MachOp, so It shouldn't be more than a few lines in the code generator to implement it.  It would be too expensive to do by default, but doing it just for Control.Monad.ST.Lazy should be ok and would fix the unsafety.</div><div><br></div><div>(I haven't really thought this through, just an idea off the top of my head, so there could well be something I'm overlooking here...)</div><div><br></div><div>Cheers</div><div>Simon</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class="gmail-HOEnZb"><div class="gmail-h5">
My view is that leaving it broken, even if it only causes trouble<br>
occasionally, is simply not an option. If users can't rely on it to always<br>
give correct answers, then it's effectively useless. And for the sake of<br>
backwards compatibility, I think it's a lot better to keep it around, even if<br>
it runs slowly multithreaded, than to remove it altogether.<br>
<br>
Note to Simon PJ: Yes, it's ugly to stick that noDup in there. But lazy ST has<br>
always been a bit of deep magic. You can't *really* carry a moment of time<br>
around in your pocket and make its history happen only if necessary. We can<br>
make it work in GHC because its execution model is entirely based around graph<br>
reduction, so evaluation is capable of driving execution. Whereas lazy IO is<br>
extremely tricky because it causes effects observable in the real world, lazy<br>
ST is only *moderately* tricky, causing effects that we have to make sure<br>
don't lead to weird interactions between threads. I don't think it's terribly<br>
surprising that it needs to do a few more weird things to work properly.<br>
<br>
David<br>
</div></div></blockquote></div><br></div></div>