[Haskell-cafe] Re: how to implement daemon start and stop directives?

Ertugrul Soeylemez es at ertes.de
Thu Jan 22 18:44:52 EST 2009


Luke Palmer <lrpalmer at gmail.com> wrote:

> On Thu, Jan 22, 2009 at 9:04 AM, Ertugrul Soeylemez <es at ertes.de> wrote:
>
> > Sometimes this is inevitable, but I've never seen a case, where
> > IORefs couldn't be replaced by a more elegant State/StateT-based
> > solution.  And if you need to do multi-threading, Chans, MVars and
> > semaphores are better anyway.
>
> Please define "better".  For the function in question, what advantages
> do they give us?

It gives you thread-safety for free, which IORefs don't give you.  It's
the same purpose, the same amount of code, but threadsafe by concept.
Of course, for simple variables, IORefs will likely be thread-safe as
well, but there is no guarantee here.  With MVars you have that
guarantee.


> Just to be clear, I wouldn't dare argue that IORefs can do everything
> MVars and TVars can do.  I'm just perplexed why you say MVars and
> TVars are better, when an IORef does the trick just fine for our
> function.

What I'm saying is:  Even if IORefs suffice, why would you want to use
them, if MVar does the job as well and likely better?


> > There is no reason to prefer an IORef over an MVar to signal
> > something to another thread.
>
> Well, I usually don't go here, but benchmarks show that IORefs are the
> fastest of any of the mutable variable primitives, by at least a
> factor of 2.  I wish I remembered where I saw that.

Yes, that's a good point, but I think, you can safely disregard that for
signalling a thread to quit.


> > By the way, IORefs are by themselves not thread-safe.  You need to
> > use a special function, when using it in a multi-threaded manner.
>
> You mean atomicModifyIORef?

Yes.


> IORefs *are* thread-safe by themselves: you will not make your program
> segfault by using them in a multithreaded program.  So it all comes
> down to invariants.  IORefs have no synchronization concepts, so code
> like:
>
>     x <- readIORef ref
>     writeIORef ref (x+1)
>
> Is not threadsafe by most standards.  That doesn't mean IORefs
> themselves are not threadsafe, just that you have to be careful how
> you use them.

That's exactly my point.  In the above case they do just the same, but
need more care.


> And I will reiterate:  *in this case* the use of IORef is fully
> encapsulated in this function and *is threadsafe!* Which is the basis
> of my argument: in imperative code, when you can limit the scope of an
> IORef to a small abstraction that is threadsafe, there is no advantage
> of TVars or MVars over them.  I don't think they deserve "bad style"
> sledgehammer.  (An instance of "use the right tool for the job")
>
> daemon :: IO () -> IO (IO ())
> daemon action = do
>     stopvar <- newIORef False
>     let run = do
>           stop <- readIORef stopvar
>           if stop then return () else (action >> run)
>     forkIO run
>     return (writeIORef stopvar True)

In this case, it's simply a coincidence that it's safe.  It's because
you're using an IORef Bool, and because writes to a Bool variable are
atomic on virtually all platforms.  An Integer may already fail to be
thread-safe.  You need more care and the payoff is zero.  If you still
insist on using IORefs, at least use the atomic function above, but that
destroys the little performance benefit of using IORefs, unless GHC does
some intelligent optimization here, which I doubt.


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/




More information about the Haskell-Cafe mailing list