Re: thread resource leaks if thread terminates with uncaught exception

Jens Thiele <[email protected]> Thu, 09 Jan 2025 12:03:47 +0100
Newsgroups gmane.lisp.scheme.gauche
Message-ID <[email protected]>
Jens Thiele <[email protected]> writes:

> 		   (pmap (lambda(i) (http-get-body))
> 			 (iota 400)
> 			 :mapper (make-fully-concurrent-mapper
> 				  0.1 'timeout)))

wanted to improve the pmap method (with fully-concurrent-mapper with
timeout):

(define-method run-map ((mapper <fully-concurrent-mapper>) proc coll)
  (let ([unique (list #f)]
        [ts (map (^e (make-thread (^[] (proc e)))) coll)]
        [timeout (absolute-time (~ mapper'timeout))]
        [timeout-val (~ mapper'timeout-val)])
    (%start-threads ts)
    (if timeout
      ($ map (^r (if (and (pair? r) (eq? (car r) unique))
                   (begin (thread-terminate! (cdr r)) timeout-val)
                   r))
         $ map (^t (thread-join! t timeout (cons unique t))) ts)
      (map thread-join! ts))))

but I am not even sure what should happen if there are multiple uncaught
exceptions. At the moment the first uncaught exception is raised by
thread-join! and then neither thread-join! nor thread-teminate! is
called on the other threads. Example session:

gosh> (use file.util)
gosh> (use control.pmap)
gosh> (define (num-threads) (length (directory-list "/proc/self/task" :children? #t)))
num-threads
gosh> (begin (guard (e [else #?=e]) (pmap (lambda(i)
					    (when (= i 1) (error "i=1"))
					    (when (= i 8) (error "i=8"))
					    (sys-sleep 2))
					  (iota 10)
					  :mapper (make-fully-concurrent-mapper 0.2 'timeout)))
	     (num-threads))
#?=e
#?-    #<uncaught-exception in thread #<thread #f (162) terminated 0 ...
12
gosh> (gc)
WARNING: A thread #f (169) died a lonely death with an uncaught exception #<error "i=8">.
#<undef>
gosh> (num-threads)
4

Best regards
Jens