Re: [Haskell-cafe] Locking, unsafePerformIO and bolt-on thread safety.

2011-05-09 Thread Erik Hesselink
My first thought was to create all of the lookup table lazily, and
create a pure top level binding for it. Something like:

lookupTable :: [Int]
lookupTable = map (\x -> unsafePerformIO (create_lookup_table x) `seq` x) [1..]

Then on a calculation you would index into this list and pass the
result as the last argument to perform_math. However, I'm not sure how
evaluation of thunks works with multiple threads; it might be possible
that this will occasionally execute create_lookup_table twice. I found
this paper [1] which suggests (in 3.5) that it does indeed, and they
suggest a primitive (justOnce :: a -> a) to prevent it. So I guess
this won't work, unless things have changed since 2005.

Erik

[1] 
http://research.microsoft.com/en-us/um/people/simonpj/papers/parallel/multiproc.pdf

On Tue, May 10, 2011 at 02:45, Jason Dusek  wrote:
>  A friend is making bindings to a C library that offers some
>  fast math operations. The normal way to use the library is
>  like this:
>
>    int a = ...; int b = ...; int c = ...; int d = ...;
>    int x                    =  ...;
>    int m, n;
>    create_lookup_table(x);
>    m                        =  perform_math(a, b, x);
>    n                        =  perform_math(c, d, x);
>
>  We see that the lookup table for x must be created before we
>  can perform math in the field/ring/what-have-you defined by x.
>  Once we have created the table, though, we're done.
>
>  My friend would like to create a pure interface to this
>  library. One thought was to write an interface to perform_math
>  that checked if the table was created, created it if not, and
>  did all this while locking an MVar so that no other instance
>  could be called at the same time, trashing the table. Doing
>  this behind unsafePerformIO would seem to be the ticket.
>
>  We end up with an implementation like this:
>
>    module FastMath where
>
>    import Control.Concurrent
>    import Foreign
>    import Foreign.C
>
>
>    foreign import ccall create_lookup_table :: CInt -> IO ()
>    foreign import ccall perform_math :: CInt -> CInt -> CInt -> IO CInt
>
>    masterLock               =  unsafePeformIO (newMVar [CInt])
>
>    safe_perform_math a b x  =  do
>      list                  <-  takeMVar masterLock
>      toPut                 <-  if not (x `elem` list)
>                                  then do create_lookup_table x
>                                          return (x:list)
>                                  else    return list
>      result                <-  perform_math a b x
>      putMVar masterLock toPut
>      return result
>
>    performMath a b x = unsafePerformIO (safe_perform_math a b x)
>
>  This does not compile but I think it gets the point across. Is
>  this approach safe? The unsafePerformIO in conjunction with
>  locking has me worried.
>
> --
> Jason Dusek
> ()  ascii ribbon campaign - against html e-mail
> /\  www.asciiribbon.org   - against proprietary attachments
>
> ___
> Haskell-Cafe mailing list
> Haskell-Cafe@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Locking, unsafePerformIO and bolt-on thread safety.

2011-05-09 Thread Jason Dusek
  A friend is making bindings to a C library that offers some
  fast math operations. The normal way to use the library is
  like this:

int a = ...; int b = ...; int c = ...; int d = ...;
int x=  ...;
int m, n;
create_lookup_table(x);
m=  perform_math(a, b, x);
n=  perform_math(c, d, x);

  We see that the lookup table for x must be created before we
  can perform math in the field/ring/what-have-you defined by x.
  Once we have created the table, though, we're done.

  My friend would like to create a pure interface to this
  library. One thought was to write an interface to perform_math
  that checked if the table was created, created it if not, and
  did all this while locking an MVar so that no other instance
  could be called at the same time, trashing the table. Doing
  this behind unsafePerformIO would seem to be the ticket.

  We end up with an implementation like this:

module FastMath where

import Control.Concurrent
import Foreign
import Foreign.C


foreign import ccall create_lookup_table :: CInt -> IO ()
foreign import ccall perform_math :: CInt -> CInt -> CInt -> IO CInt

masterLock   =  unsafePeformIO (newMVar [CInt])

safe_perform_math a b x  =  do
  list  <-  takeMVar masterLock
  toPut <-  if not (x `elem` list)
  then do create_lookup_table x
  return (x:list)
  elsereturn list
  result<-  perform_math a b x
  putMVar masterLock toPut
  return result

performMath a b x = unsafePerformIO (safe_perform_math a b x)

  This does not compile but I think it gets the point across. Is
  this approach safe? The unsafePerformIO in conjunction with
  locking has me worried.

--
Jason Dusek
()  ascii ribbon campaign - against html e-mail
/\  www.asciiribbon.org   - against proprietary attachments

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe