* ice-9 thread-pool
@ 2012-02-06 19:14 Andy Wingo
2012-02-06 22:55 ` Ludovic Courtès
2012-02-08 4:03 ` Nala Ginrut
0 siblings, 2 replies; 5+ messages in thread
From: Andy Wingo @ 2012-02-06 19:14 UTC (permalink / raw)
To: guile-devel
[-- Attachment #1: Type: text/plain, Size: 97 bytes --]
Hi,
Related to my previous mail, here is a thread pool implementation.
Comments welcome.
Andy
[-- Attachment #2: ice-9 thread-pool --]
[-- Type: text/plain, Size: 5727 bytes --]
;;; Thread pools
;; Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
;; This library is free software; you can redistribute it and/or
;; modify it under the terms of the GNU Lesser General Public
;; License as published by the Free Software Foundation; either
;; version 3 of the License, or (at your option) any later version.
;;
;; This library is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; Lesser General Public License for more details.
;;
;; You should have received a copy of the GNU Lesser General Public
;; License along with this library; if not, write to the Free Software
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
;; 02110-1301 USA
;;; Commentary:
;;;
;;; A simple thread pool implementation.
;;;
;;; Code:
(define-module (ice-9 thread-pool)
#:use-module (srfi srfi-9)
#:use-module (srfi srfi-9 gnu)
#:use-module (ice-9 threads)
#:export (make-thread-pool
start-thread-pool!
pause-thread-pool!
stop-thread-pool!))
(define-record-type <worker>
(%make-worker mutex condvar thread handler state)
worker?
(mutex worker-mutex)
(condvar worker-condvar)
(thread worker-thread set-worker-thread!)
(handler worker-handler)
(state worker-state set-worker-state!))
(define (make-worker handler)
(%make-worker (make-mutex) (make-condition-variable) #f handler 'stopped))
(define* (worker-wait worker #:optional time)
(if time
(wait-condition-variable (worker-condvar worker)
(worker-mutex worker)
time)
(wait-condition-variable (worker-condvar worker)
(worker-mutex worker))))
(define (worker-stopping? worker)
(with-mutex (worker-mutex worker)
(let lp ()
(case (worker-state worker)
((running)
#f)
((pausing)
(set-worker-state! worker 'paused)
(signal-condition-variable (worker-condvar worker))
(lp))
((paused)
(worker-wait worker)
(lp))
((stopping)
#t)
(else
(error "bad state" worker))))))
(define (worker-loop worker)
(let lp ()
(or (worker-stopping? worker)
(begin
((worker-handler worker))
(lp)))))
(define (pause-worker worker)
(with-mutex (worker-mutex worker)
(let lp ()
(case (worker-state worker)
((running)
(set-worker-state! worker 'pausing)
(lp))
((pausing)
#f)
((paused)
#t)
((stopping)
(error "attempt to go stopping -> pausing" worker))
((stopped)
(set-worker-state! worker 'pausing)
(set-worker-thread! worker
(make-thread worker-loop worker))
(lp))
(else
(error "bad state" worker))))))
(define* (wait-for-paused worker #:optional time)
(with-mutex (worker-mutex worker)
(let lp ()
(case (worker-state worker)
((paused)
#t)
(else
(and (worker-wait worker time)
(lp)))))))
(define (start-worker worker)
(with-mutex (worker-mutex worker)
(let lp ()
(case (worker-state worker)
((running)
#t)
((stopping)
(error "attempt to go stopping -> running" worker))
(else
(set-worker-state! worker 'running)
(if (worker-thread worker)
(signal-condition-variable (worker-condvar worker))
(set-worker-thread! worker (make-thread worker-loop worker)))
(lp))))))
(define (stop-worker worker)
(with-mutex (worker-mutex worker)
(let lp ()
(case (worker-state worker)
((stopped)
#t)
((stopping)
#f)
(else
(set-worker-state! worker 'stopping)
(lp))))))
(define* (wait-for-stopped worker #:optional time #:key cancel?)
(let ((thread
(with-mutex (worker-mutex worker)
(cond
((eq? (worker-state worker) 'stopped)
#f)
((thread-exited? (worker-thread worker))
(set-worker-thread! worker #f)
(set-worker-state! worker 'stopped)
#f)
(else
(worker-thread worker))))))
(or (not thread)
(begin
(if time
(join-thread (worker-thread worker) time)
(join-thread (worker-thread worker)))
(cond
((thread-exited? thread)
(wait-for-stopped worker))
(cancel?
(cancel-thread (worker-thread worker))
;; Assume it works.
(join-thread (worker-thread worker))
(wait-for-stopped worker))
(else
#f))))))
(define-record-type <thread-pool>
(%make-thread-pool size workers)
thread-pool?
(size thread-pool-size)
(workers thread-pool-workers))
;; Create a thread pool, and bring it to the "paused" state.
;;
(define (make-thread-pool size handler)
(let ((pool (%make-thread-pool size
(map (lambda (i) (make-worker handler))
(iota size)))))
(pause-thread-pool! pool)
pool))
(define (pause-thread-pool! pool)
(for-each pause-worker (thread-pool-workers pool))
(for-each wait-for-paused (thread-pool-workers pool)))
(define (start-thread-pool! pool)
(for-each start-worker (thread-pool-workers pool)))
(define (stop-thread-pool! pool)
(for-each stop-worker (thread-pool-workers pool))
(for-each wait-for-stopped (thread-pool-workers pool)))
[-- Attachment #3: Type: text/plain, Size: 26 bytes --]
--
http://wingolog.org/
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: ice-9 thread-pool
2012-02-06 19:14 ice-9 thread-pool Andy Wingo
@ 2012-02-06 22:55 ` Ludovic Courtès
2012-02-08 4:03 ` Nala Ginrut
1 sibling, 0 replies; 5+ messages in thread
From: Ludovic Courtès @ 2012-02-06 22:55 UTC (permalink / raw)
To: guile-devel
Hi Andy!
Andy Wingo <wingo@pobox.com> skribis:
> Related to my previous mail, here is a thread pool implementation.
> Comments welcome.
What use case do you have in mind? “Thread pool” seems too generic to
really have anything to say about it. :-)
Thanks,
Ludo’.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: ice-9 thread-pool
2012-02-06 19:14 ice-9 thread-pool Andy Wingo
2012-02-06 22:55 ` Ludovic Courtès
@ 2012-02-08 4:03 ` Nala Ginrut
2012-02-08 9:47 ` Andy Wingo
1 sibling, 1 reply; 5+ messages in thread
From: Nala Ginrut @ 2012-02-08 4:03 UTC (permalink / raw)
To: Andy Wingo; +Cc: guile-devel
[-- Attachment #1: Type: text/plain, Size: 6346 bytes --]
Well, what if I want to avoid to create new thread repeatedly?
I mean recycle or pre-allocate a bunch of threads, then reuse them.
How can I reuse a thread-object in Guile?
On Tue, Feb 7, 2012 at 3:14 AM, Andy Wingo <wingo@pobox.com> wrote:
> Hi,
>
> Related to my previous mail, here is a thread pool implementation.
> Comments welcome.
>
> Andy
>
>
> ;;; Thread pools
>
> ;; Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
>
> ;; This library is free software; you can redistribute it and/or
> ;; modify it under the terms of the GNU Lesser General Public
> ;; License as published by the Free Software Foundation; either
> ;; version 3 of the License, or (at your option) any later version.
> ;;
> ;; This library is distributed in the hope that it will be useful,
> ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> ;; Lesser General Public License for more details.
> ;;
> ;; You should have received a copy of the GNU Lesser General Public
> ;; License along with this library; if not, write to the Free Software
> ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> ;; 02110-1301 USA
>
> ;;; Commentary:
> ;;;
> ;;; A simple thread pool implementation.
> ;;;
> ;;; Code:
>
> (define-module (ice-9 thread-pool)
> #:use-module (srfi srfi-9)
> #:use-module (srfi srfi-9 gnu)
> #:use-module (ice-9 threads)
> #:export (make-thread-pool
> start-thread-pool!
> pause-thread-pool!
> stop-thread-pool!))
>
>
> (define-record-type <worker>
> (%make-worker mutex condvar thread handler state)
> worker?
> (mutex worker-mutex)
> (condvar worker-condvar)
> (thread worker-thread set-worker-thread!)
> (handler worker-handler)
> (state worker-state set-worker-state!))
>
> (define (make-worker handler)
> (%make-worker (make-mutex) (make-condition-variable) #f handler 'stopped))
>
> (define* (worker-wait worker #:optional time)
> (if time
> (wait-condition-variable (worker-condvar worker)
> (worker-mutex worker)
> time)
> (wait-condition-variable (worker-condvar worker)
> (worker-mutex worker))))
>
> (define (worker-stopping? worker)
> (with-mutex (worker-mutex worker)
> (let lp ()
> (case (worker-state worker)
> ((running)
> #f)
> ((pausing)
> (set-worker-state! worker 'paused)
> (signal-condition-variable (worker-condvar worker))
> (lp))
> ((paused)
> (worker-wait worker)
> (lp))
> ((stopping)
> #t)
> (else
> (error "bad state" worker))))))
>
> (define (worker-loop worker)
> (let lp ()
> (or (worker-stopping? worker)
> (begin
> ((worker-handler worker))
> (lp)))))
>
> (define (pause-worker worker)
> (with-mutex (worker-mutex worker)
> (let lp ()
> (case (worker-state worker)
> ((running)
> (set-worker-state! worker 'pausing)
> (lp))
> ((pausing)
> #f)
> ((paused)
> #t)
> ((stopping)
> (error "attempt to go stopping -> pausing" worker))
> ((stopped)
> (set-worker-state! worker 'pausing)
> (set-worker-thread! worker
> (make-thread worker-loop worker))
> (lp))
> (else
> (error "bad state" worker))))))
>
> (define* (wait-for-paused worker #:optional time)
> (with-mutex (worker-mutex worker)
> (let lp ()
> (case (worker-state worker)
> ((paused)
> #t)
> (else
> (and (worker-wait worker time)
> (lp)))))))
>
> (define (start-worker worker)
> (with-mutex (worker-mutex worker)
> (let lp ()
> (case (worker-state worker)
> ((running)
> #t)
> ((stopping)
> (error "attempt to go stopping -> running" worker))
> (else
> (set-worker-state! worker 'running)
> (if (worker-thread worker)
> (signal-condition-variable (worker-condvar worker))
> (set-worker-thread! worker (make-thread worker-loop worker)))
> (lp))))))
>
> (define (stop-worker worker)
> (with-mutex (worker-mutex worker)
> (let lp ()
> (case (worker-state worker)
> ((stopped)
> #t)
> ((stopping)
> #f)
> (else
> (set-worker-state! worker 'stopping)
> (lp))))))
>
> (define* (wait-for-stopped worker #:optional time #:key cancel?)
> (let ((thread
> (with-mutex (worker-mutex worker)
> (cond
> ((eq? (worker-state worker) 'stopped)
> #f)
> ((thread-exited? (worker-thread worker))
> (set-worker-thread! worker #f)
> (set-worker-state! worker 'stopped)
> #f)
> (else
> (worker-thread worker))))))
> (or (not thread)
> (begin
> (if time
> (join-thread (worker-thread worker) time)
> (join-thread (worker-thread worker)))
> (cond
> ((thread-exited? thread)
> (wait-for-stopped worker))
> (cancel?
> (cancel-thread (worker-thread worker))
> ;; Assume it works.
> (join-thread (worker-thread worker))
> (wait-for-stopped worker))
> (else
> #f))))))
>
> (define-record-type <thread-pool>
> (%make-thread-pool size workers)
> thread-pool?
> (size thread-pool-size)
> (workers thread-pool-workers))
>
> ;; Create a thread pool, and bring it to the "paused" state.
> ;;
> (define (make-thread-pool size handler)
> (let ((pool (%make-thread-pool size
> (map (lambda (i) (make-worker handler))
> (iota size)))))
> (pause-thread-pool! pool)
> pool))
>
> (define (pause-thread-pool! pool)
> (for-each pause-worker (thread-pool-workers pool))
> (for-each wait-for-paused (thread-pool-workers pool)))
>
> (define (start-thread-pool! pool)
> (for-each start-worker (thread-pool-workers pool)))
>
> (define (stop-thread-pool! pool)
> (for-each stop-worker (thread-pool-workers pool))
> (for-each wait-for-stopped (thread-pool-workers pool)))
>
>
> --
> http://wingolog.org/
>
>
[-- Attachment #2: Type: text/html, Size: 8105 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: ice-9 thread-pool
2012-02-08 4:03 ` Nala Ginrut
@ 2012-02-08 9:47 ` Andy Wingo
2012-02-08 13:39 ` Ludovic Courtès
0 siblings, 1 reply; 5+ messages in thread
From: Andy Wingo @ 2012-02-08 9:47 UTC (permalink / raw)
To: Nala Ginrut; +Cc: guile-devel
On Wed 08 Feb 2012 05:03, Nala Ginrut <nalaginrut@gmail.com> writes:
> Well, what if I want to avoid to create new thread repeatedly?
> I mean recycle or pre-allocate a bunch of threads, then reuse them.
> How can I reuse a thread-object in Guile?
If I understand you correctly, you would use a thread pool. You'd build
it yourself. (Of course, if this patch goes in, you'd use it instead.)
Andy
--
http://wingolog.org/
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: ice-9 thread-pool
2012-02-08 9:47 ` Andy Wingo
@ 2012-02-08 13:39 ` Ludovic Courtès
0 siblings, 0 replies; 5+ messages in thread
From: Ludovic Courtès @ 2012-02-08 13:39 UTC (permalink / raw)
To: guile-devel
Hi,
Andy Wingo <wingo@pobox.com> skribis:
> On Wed 08 Feb 2012 05:03, Nala Ginrut <nalaginrut@gmail.com> writes:
>
>> Well, what if I want to avoid to create new thread repeatedly?
>> I mean recycle or pre-allocate a bunch of threads, then reuse them.
>> How can I reuse a thread-object in Guile?
>
> If I understand you correctly, you would use a thread pool. You'd build
> it yourself. (Of course, if this patch goes in, you'd use it instead.)
Heheh. :-)
I was asking this question because I view thread pools as an
implementation technique, not as an API.
The API would be futures for computation, and something different for
asynchronous I/O. For example, Oleg K. shows a nice approach to that
similar to futures at <http://okmij.org/ftp/meta-future/>.
Thanks,
Ludo’.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-02-08 13:39 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-06 19:14 ice-9 thread-pool Andy Wingo
2012-02-06 22:55 ` Ludovic Courtès
2012-02-08 4:03 ` Nala Ginrut
2012-02-08 9:47 ` Andy Wingo
2012-02-08 13:39 ` Ludovic Courtès
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).