Finalizer registered with System.Mem.Weak.addFinalizer is called surprisingly early

Hello, I use addFinalizer from System.Mem.Weak for performing some actions on data just before that is reclaimed by GC. Registered in this way finalizer is called surprisingly early for me, much earlier the data is tend to be collected. I've attached source code of simple two-threaded program. Source code also can be found at [1]. It is pretty simple and should be readable enough. Program is intentioned to pass messages through transactional variable (TVar) for printing by worker thread. Messages consist of formatted to String Int values from 1 to 1000000. So the output should look like this:
1 2 ... 1000000
But running the program gives something like that:
1 2 ... 283 finalizing Test: thread blocked indefinitely in an STM transaction
As far as I see, finalizer is called too early. If someone could point me out how to do the right thing, that would be helpful. Operaton system: Debian Squeeze Compiler: GHC 6.12.1 Compiling options: none, just "ghc --make Test.hs" Thanks, balodja [1] http://hpaste.org/44648

On Wed, Mar 9, 2011 at 3:54 PM, balodja
Hello,
I use addFinalizer from System.Mem.Weak for performing some actions on data just before that is reclaimed by GC. Registered in this way finalizer is called surprisingly early for me, much earlier the data is tend to be collected.
I've attached source code of simple two-threaded program. Source code also can be found at [1]. It is pretty simple and should be readable enough.
Does it work if you change:
forM_ [1..1000000] $ \x -> do send socket (show x) threadDelay (10*1000)
to:
forM_ [1..1000000] $ \x -> do send socket (show x) touch socket threadDelay (10*1000)
Where "touch" is found in Control.Monad.Primitive of the package "primitive": http://hackage.haskell.org/packages/archive/primitive/0.3.1/doc/html/Control... I'm guessing what happens is that optimizations make the 'Socket' constructor go away, so the finalizer runs as soon as it can. The 'touch' function might force it to stick around. You'll probably want to look at the low-level compiler output to make sure: http://hackage.haskell.org/package/ghc-core Does anyone else have any good tutorials to link to? Antoine
Program is intentioned to pass messages through transactional variable (TVar) for printing by worker thread. Messages consist of formatted to String Int values from 1 to 1000000. So the output should look like this:
1 2 ... 1000000
But running the program gives something like that:
1 2 ... 283 finalizing Test: thread blocked indefinitely in an STM transaction
As far as I see, finalizer is called too early. If someone could point me out how to do the right thing, that would be helpful.
Operaton system: Debian Squeeze Compiler: GHC 6.12.1 Compiling options: none, just "ghc --make Test.hs"
Thanks, balodja
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Thank you for your answer.
Does it work if you change:
forM_ [1..1000000] $ \x -> do send socket (show x) threadDelay (10*1000)
to:
forM_ [1..1000000] $ \x -> do send socket (show x) touch socket threadDelay (10*1000)
Yes, that works.
I'm guessing what happens is that optimizations make the 'Socket' constructor go away, so the finalizer runs as soon as it can. The 'touch' function might force it to stick around. You'll probably want to look at the low-level compiler output to make sure:
As far as I see you are definitely right. Due to good inlining Socket constructor is not needed in main forM-cycle. After some meditation on core output I added NOINLINE pragma to function "send" and the problem vanished. Is NOINLINE pragma a good workaround in such situation? Thanks, balodja
participants (2)
-
Antoine Latter
-
balodja