From: Peter Keller on
Hello,

I'm using SBCL 1.0.33.30 and the Bordeaux Thread package. My question is in
this piece of code:

(unwind-protect
(while t
;; set up some data
(push
(make-thread #'work-func)
*thread-list))

; cleanup of uw-p
(mapc #'(lamdba (thr)
(when (thread-alive-p thr)
(destroy-thread thr)))))


I see two possibilities for race conditions:

1. If the make-thread completes, and before the push happens, the form
stops evaluation through condition (how it would get signaled there I
don't know) or breaking into the debugger and going back to the top level
(which I was unlucky enough to actually perform by hand).

2. The thread completes after thread-alive-p states it was alive but before
destroy-thread evaluates.

For number 2, I chose to solve the problem of the signaled condition by
destroy-thread with (ignore-errors ...), but I have no idea how to solve
number 1. As far as I can tell a thread could be failed to be cleaned
up under the right circumstances and left running.

Are there any idiomatic ways to deal with this problem? I want to ensure that
if the program I'm running is forced to quit, all threads are cleaned up.

Thank you.

-pete
From: vanekl on
On Mar 3, 1:49 pm, Peter Keller <psil...(a)merlin.cs.wisc.edu> wrote:
> Hello,
>
> I'm using SBCL 1.0.33.30 and the Bordeaux Thread package. My question is in
> this piece of code:
>
> (unwind-protect
>   (while t
>     ;; set up some data
>     (push
>       (make-thread #'work-func)
>       *thread-list))
>
>   ; cleanup of uw-p
>   (mapc #'(lamdba (thr)
>       (when (thread-alive-p thr)
>         (destroy-thread thr)))))
>
> I see two possibilities for race conditions:
>
> 1. If the make-thread completes, and before the push happens, the form
> stops evaluation through condition (how it would get signaled there I
> don't know) or breaking into the debugger and going back to the top level
> (which I was unlucky enough to actually perform by hand).
>
> 2. The thread completes after thread-alive-p states it was alive but before
> destroy-thread evaluates.
>
> For number 2, I chose to solve the problem of the signaled condition by
> destroy-thread with (ignore-errors ...), but I have no idea how to solve
> number 1. As far as I can tell a thread could be failed to be cleaned
> up under the right circumstances and left running.
>
> Are there any idiomatic ways to deal with this problem? I want to ensure that
> if the program I'm running is forced to quit, all threads are cleaned up.
>
> Thank you.
>
> -pete

(use-package :sb-thread)

(defun kill-my-thread (tgt-thread-name)
(map nil
(lambda (thread)
(let ((name (thread-name thread)))
(if (equalp tgt-thread-name name)
(progn
(format t "killing thread ~s~%" name)
(terminate-thread thread))
(format t "alive: ~a~%" name))))
(list-all-threads)))

(progn
(terpri)
(let ((s *standard-output*))
(make-thread (lambda ()
(format s "~%Kill me!~%")
(force-output)
(sleep 10))
:name "test-thread"))
(kill-my-thread "test-thread"))
From: Peter Keller on
vanekl <vanek(a)acd.net> wrote:
> On Mar 3, 1:49?pm, Peter Keller <psil...(a)merlin.cs.wisc.edu> wrote:

[ I mention a couple race conditions in the below code ]

[ this code below is adjusted, it had a stupid typo in it]

>> (unwind-protect
>> (while t
>> ;; set up some data
>> (push
>> (make-thread #'work-func)
>> *thread-list*))
>>
>> ; cleanup of uw-p
>> (mapc #'(lamdba (thr)
>> (when (thread-alive-p thr)
>> (destroy-thread thr)))
>> *thread-list*))

>> Are there any idiomatic ways to deal with this problem? I want to ensure that
>> if the program I'm running is forced to quit, all threads are cleaned up.

> (use-package :sb-thread)
>
> (defun kill-my-thread (tgt-thread-name)
> (map nil
> (lambda (thread)
> (let ((name (thread-name thread)))
> (if (equalp tgt-thread-name name)
> (progn
> (format t "killing thread ~s~%" name)
> (terminate-thread thread))
> (format t "alive: ~a~%" name))))
> (list-all-threads)))
>
> (progn
> (terpri)
> (let ((s *standard-output*))
> (make-thread (lambda ()
> (format s "~%Kill me!~%")
> (force-output)
> (sleep 10))
> :name "test-thread"))
> (kill-my-thread "test-thread"))

So the idiomatic method you suggest is I should use bordeaux threads'
(all-threads) to enumerate the threads instead of keeping the thread list
manually? This is in the hopes that the list returned by all-threads is
properly set up by bordeaux threads? Also, I'd like to keep the solution
in bordaeux threads.

Thank you.

-pete




From: vanekl on
On Mar 3, 3:22 pm, Peter Keller <psil...(a)merlin.cs.wisc.edu> wrote:
> vanekl <va...(a)acd.net> wrote:
> > On Mar 3, 1:49?pm, Peter Keller <psil...(a)merlin.cs.wisc.edu> wrote:
>
> [ I mention a couple race conditions in the below code ]
>
> [ this code below is adjusted, it had a stupid typo in it]
>
>
>
> >> (unwind-protect
> >>   (while t
> >>     ;; set up some data
> >>     (push
> >>       (make-thread #'work-func)
> >>       *thread-list*))
>
> >>   ; cleanup of uw-p
> >>   (mapc #'(lamdba (thr)
> >>       (when (thread-alive-p thr)
> >>         (destroy-thread thr)))
> >>    *thread-list*))
> >> Are there any idiomatic ways to deal with this problem? I want to ensure that
> >> if the program I'm running is forced to quit, all threads are cleaned up.
> > (use-package :sb-thread)
>
> > (defun kill-my-thread (tgt-thread-name)
> >  (map nil
> >       (lambda (thread)
> >         (let ((name (thread-name thread)))
> >           (if (equalp tgt-thread-name name)
> >               (progn
> >                 (format t "killing thread ~s~%" name)
> >                 (terminate-thread thread))
> >               (format t "alive: ~a~%" name))))
> >       (list-all-threads)))
>
> > (progn
> >  (terpri)
> >  (let ((s *standard-output*))
> >    (make-thread (lambda ()
> >                             (format s "~%Kill me!~%")
> >                             (force-output)
> >                             (sleep 10))
> >                           :name "test-thread"))
> >  (kill-my-thread "test-thread"))
>
> So the idiomatic method you suggest is I should use bordeaux threads'
> (all-threads) to enumerate the threads instead of keeping the thread list
> manually? This is in the hopes that the list returned by all-threads is
> properly set up by bordeaux threads? Also, I'd like to keep the solution
> in bordaeux threads.
>
> Thank you.
>
> -pete

Yes, if you are worried about zombie threads and another package is
already managing live threads, I would rely upon that package instead
of duplicating effort (and possibly introducing errors).
From: Peter Keller on
vanekl <vanek(a)acd.net> wrote:
> On Mar 3, 3:22?pm, Peter Keller <psil...(a)merlin.cs.wisc.edu> wrote:
>> So the idiomatic method you suggest is I should use bordeaux threads'
>> (all-threads) to enumerate the threads instead of keeping the thread list
>> manually? This is in the hopes that the list returned by all-threads is
>> properly set up by bordeaux threads? Also, I'd like to keep the solution
>> in bordaeux threads.
>>
> Yes, if you are worried about zombie threads and another package is
> already managing live threads, I would rely upon that package instead
> of duplicating effort (and possibly introducing errors).

Good point.

Thank you!

-pete
 | 
Pages: 1
Prev: Loop syntax style
Next: NoSQL Movement?