[Haskell-cafe] Spurious program crashes

Sebastian Sylvan sebastian.sylvan at gmail.com
Thu Nov 17 09:03:56 EST 2005


On 11/17/05, Joel Reymont <joelr1 at gmail.com> wrote:
>
> On Nov 17, 2005, at 1:44 PM, Sebastian Sylvan wrote:
>
> > Are you sure it's safe to kill a thread which has already been killed?
>
> It seems so from the docs.
>
> > Why do you fork off the killing of the threads? Why not just run them
> > in sequence?
>
> Someone said that they read somewhere that killThread can block. I'm
> not gonna point any fingers at musasabi ;-).
>
> > Also, I'd recommend refactoring the code a bit, write a function
> > "parIO" which runs IO computations in parallell and then define
> > timeout in terms of that.
>
> I did this by stealing the timeout/either combinators from the
> Asynchronous Exceptions paper. It did not help a single bit.
>


This is somewhat frustrating for me because I had a very similar (if
not the exact same) issue when writing some test applications for an
FMOD binding. However, all that source code (and so much more) was
lost due to a hard disk failure. I am now struggling to remember what
was the cause, and how I solved.

What I do remember is that the timeout and parIO functions in the
concurrent programming papers I found were NOT correct. killThread did
NOT behave as expected when I killed an already killed thread.
I tried multiple tricks here (including some which required recursive
do-notation) to try to get the parIO function to only kill the *other*
thread.
This could be done by having the two spawned threads take their
computations in an MVar along with the threadID of the other thread.

something like:

parIO f1 f2 = do m <- newEmptyMVar -- result Mvar
                       mf1 <- newEmptyMVar  -- MVar for f1
                       mf2 <- newEmptyMVar  -- MVar for f2
                       -- fork worker threads
                       t1 <- forkIO (child m mf1)
                       t2 <- forkIO (child m mf2)

                       -- pass computations and threadID to worker threads
                       putMVar mf1 (t2, f1)
                       putMVar mf2 (t1, f2)

                       -- return result
                       takeMVar m
                       where child m mf = do (tid, f) <- takeMVar mf
                                                        x <- f
                                                        putMVar m x
                                                        killThread tid


timeout t f = threadDelay (round (t * 1e6)) `parIO` f


As I remember another solution I came up with was to wrap the "child"
function body in a catch statement. The child function was just a
helper function that ran a computation and put its result in an MVar.

I *think* the problem *may* have been that when an FFI function got
"ThreadKilled" exception asynchrounously that got bubbled up to the
parIO thread for some reason.

/S

--
Sebastian Sylvan
+46(0)736-818655
UIN: 44640862


More information about the Haskell-Cafe mailing list