Arc Forumnew | comments | leaders | submitlogin
Bug in atomic when using kill-thread
2 points by akkartik 5273 days ago | 10 comments
kill-thread doesn't respect atomic, so the dead thread can be left holding the atomic semaphore. Other threads will then block forever the first time they try to perform assignment.

  arc> (= l (thread:atomic (while t)))
  #<thread: l>
  arc> (= a nil)
  nil
  arc> (kill-thread l)
  #<void>
  arc> (dead l)
  t
  arc> (push 3 a)
  ;; hangs
Reading the mzscheme docs, it seems to me that kill-thread respects scheme's guarantees of atomicity. But arc simulates its own atomic, which has slipped through the cracks.

The use case for kill-thread is a timeout macro that runs a computation for some time and then stops it.

I don't see how to fix kill-thread without completely changing how atomic is implemented. I thought of recording which thread holds the semaphore, but there's no way to 'break' a semaphore within kill-thread, is there?



1 point by akkartik 5273 days ago | link

D'oh I should just make kill-thread atomic :)

  (def kill-thread(th)
    (atomic ($:kill-thread th)))
  (def break-thread(th)
    (atomic ($:break-thread th)))
It won't help with the example above, but it should suffice for realistic scenarios:

  arc> (= l (thread (atomic (sleep 5)) (while t)))
  #<thread: l>
  arc> (kill-thread l)
  ;; pause
  #<void>
  arc> (= a nil)
  nil
  arc> (push 3 a)
  (3)

-----

2 points by aw 5273 days ago | link

Not sure if MzScheme's kill-thread is guaranteed to kill a thread "instantly"? If not, then you have a race condition: you schedule a thread to be killed, but it maybe has just enough time to enter an atomic block before it dies.

But you're on the right track though. We actually don't want to kill a thread in the middle of an atomic... in your very first example, (thread:atomic (while t)), it would be a bug if kill-thread did break that loop. The whole point of "atomic" is that the operation completes before other threads see the result.

So the desired behavior is if a thread is "killed" in the middle of an atomic block, it should finish the block (and release the lock in the normal way), and then die.

The MzScheme documentation web site is down at the moment so I can't look now, but if I recall there is some kind of break or signal mechanism in MzScheme that might help.

-----

1 point by elibarzilay 5273 days ago | link

The documentation server is back up.

-----

1 point by akkartik 5273 days ago | link

Still down for me, but from google's cache:

"Terminates the specified thread immediately, or suspends the thread if thd was created with thread/suspend-to-kill." http://74.125.155.132/search?q=cache:kdhjq2ukTtgJ:download.p...

So it seems kill-thread is guaranteed to kill the thread by the time it returns.

-----

1 point by akkartik 5272 days ago | link

Oh, but break-thread is not: "Registers a break with the specified thread." http://docs.plt-scheme.org/reference/threads.html#%28def._%2... "When a break is detected and enabled, the exn:break exception is raised in the thread sometime afterward" http://docs.plt-scheme.org/reference/breakhandler.html

-----

1 point by rntz 5273 days ago | link

That doesn't help if you want to kill a thread which is stuck (or just taking a long time) within an (atomic ...) expression, which seems to me an important use case. Unfortunately the plt doc website appears to be down now, otherwise I'd look into solving it myself.

-----

1 point by akkartik 5273 days ago | link

True, but that sounds like an enhancement to the semantics of atomic (a way to interrupt an atomic operation) rather than a bug in kill-thread.

-----

1 point by aw 5273 days ago | link

There shouldn't be a way to interrupt an atomic operation, because then it won't be atomic.

Your elegant solution to make kill-thread atomic is a good one, if the "killed" thread is in fact guaranteed to be terminated instantly... I'll have to look into it to see if I can find out.

-----

1 point by akkartik 5273 days ago | link

There shouldn't be a way to interrupt an atomic operation, because then it won't be atomic.

An interruptable atomic is basically a transaction that can be rolled back. If it gets interrupted nothing is changed. Probably doesn't make sense to run it from anywhere but kill-thread and similar operations.

To restate my original point: reasonable semantics for atomic are that threads inside atomic can't be killed. How to kill long-running atomics is a separate issue, needing a lot more engineering.

-----

1 point by aw 5273 days ago | link

reasonable semantics for atomic are that threads inside atomic can't be killed

We agree.

-----