<div dir="ltr">There is extra work done to make this safe.  See the following:<div><br></div><div><a href="https://github.com/ghc/ghc/blob/af6746fb6b5adb5ba5be6e0f647c4ebe767ce084/rts/sm/Storage.c#L305">https://github.com/ghc/ghc/blob/af6746fb6b5adb5ba5be6e0f647c4ebe767ce084/rts/sm/Storage.c#L305</a><br>
</div><div><a href="https://ghc.haskell.org/trac/ghc/ticket/5558">https://ghc.haskell.org/trac/ghc/ticket/5558</a><br></div><div><br></div><div>Ryan</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, May 1, 2014 at 8:25 AM, Mikulas Patocka <span dir="ltr"><<a href="mailto:mikulas@artax.karlin.mff.cuni.cz" target="_blank">mikulas@artax.karlin.mff.cuni.cz</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">> Also note linked from the global variables page on the wiki is:<br>
> <a href="http://www.haskell.org/haskellwiki/Top_level_mutable_state" target="_blank">http://www.haskell.org/haskellwiki/Top_level_mutable_state</a><br>
><br>
> Important for the `unsafePerformIO` option is the NOINLINE pragma to ensure<br>
> that only one global variable exists.  In the STM case it is also important<br>
> to use `newTVarIO` rather then `unsafePerformIO $ atomically newTVar` which<br>
> does not work.<br>
><br>
> Ryan<br>
<br>
Hi<br>
<br>
I think it isn't correct even with NOINLINE.<br>
<br>
<br>
Read the paper "Haskell on a Shared-Memory Multiprocessor"<br>
<a href="http://research.microsoft.com/pubs/67424/2005-haskell.pdf" target="_blank">http://research.microsoft.com/pubs/67424/2005-haskell.pdf</a><br>
<br>
Among other things, the paper presents these ideas:<br>
<br>
(section 3.1) When multiple threads start to evaluate the same thunk<br>
concurrently, we could use interlocked compare-and-swap instruction to<br>
make sure that only one thread starts to evaluate it. However, the<br>
compare-and-swap instruction is slow and executing it at every thunk<br>
evaluation decreases performance. So, the designers avoid the<br>
compare-and-swap instruction (section 3.2) and consequently there is a<br>
race condition - there is a small window where two or more threads may<br>
evaluate the same thunk concurrently.<br>
<br>
Normally, this race condition doesn't matter, because Haskell is purely<br>
functional language, so when multiple threads evaluate the same thunk they<br>
end up with the same result - but in this particular example, where one is<br>
using unsafePerformIO to construct a unique variable, it can hurt, because<br>
you end up executing "unsafePerformIO $ newMVar 0" concurrently (section<br>
3.5 of the paper).<br>
<br>
<br>
So - code like this isn't correct, the numbers returned by "uniq" may not<br>
be unique if we hit the race condition when evaluating "global":<br>
<br>
global :: MVar Integer<br>
global = unsafePerformIO $ newMVar 0<br>
{-# NOINLINE global #-}<br>
uniq = modifyMVar global (\i -> return (i+1,i))<br>
<br>
<br>
Has anything changed since that time, so that this construct is safe?<br>
<span class="HOEnZb"><font color="#888888"><br>
Mikulas<br>
</font></span></blockquote></div><br></div>