1 ;;;; Copyright (C) 1996, 1998, 2001, 2002, 2003, 2006, 2010, 2011,
2 ;;;; 2012 Free Software Foundation, Inc.
4 ;;;; This library is free software; you can redistribute it and/or
5 ;;;; modify it under the terms of the GNU Lesser General Public
6 ;;;; License as published by the Free Software Foundation; either
7 ;;;; version 3 of the License, or (at your option) any later version.
9 ;;;; This library is distributed in the hope that it will be useful,
10 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ;;;; Lesser General Public License for more details.
14 ;;;; You should have received a copy of the GNU Lesser General Public
15 ;;;; License along with this library; if not, write to the Free Software
16 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 ;;;; ----------------------------------------------------------------
19 ;;;; threads.scm -- User-level interface to Guile's thread system
20 ;;;; 4 March 1996, Anthony Green <green@cygnus.com>
21 ;;;; Modified 5 October 1996, MDJ <djurfeldt@nada.kth.se>
22 ;;;; Modified 6 April 2001, ttn
23 ;;;; ----------------------------------------------------------------
28 ;; This module is documented in the Guile Reference Manual.
29 ;; Briefly, one procedure is exported: `%thread-handler';
30 ;; as well as four macros: `make-thread', `begin-thread',
31 ;; `with-mutex' and `monitor'.
35 (define-module (ice-9 threads)
36 #:use-module (ice-9 futures)
37 #:use-module (ice-9 match)
38 #:export (begin-thread
54 ;;; Macros first, so that the procedures expand correctly.
56 (define-syntax-rule (begin-thread e0 e1 ...)
61 (define-syntax parallel
65 (with-syntax (((tmp0 ...) (generate-temporaries (syntax (e0 ...)))))
66 #'(let ((tmp0 (future e0))
68 (values (touch tmp0) ...)))))))
70 (define-syntax-rule (letpar ((v e) ...) b0 b1 ...)
72 (lambda () (parallel e ...))
76 (define-syntax-rule (make-thread proc arg ...)
78 (lambda () (proc arg ...))
81 (define-syntax-rule (with-mutex m e0 e1 ...)
84 (lambda () (lock-mutex x))
85 (lambda () (begin e0 e1 ...))
86 (lambda () (unlock-mutex x)))))
88 (define-syntax-rule (monitor first rest ...)
89 (with-mutex (make-mutex)
92 (define (par-mapper mapper cons)
93 (lambda (proc . lists)
94 (let loop ((lists lists))
96 (((heads tails ...) ...)
97 (let ((tail (future (loop tails)))
98 (head (apply proc heads)))
99 (cons head (touch tail))))
103 (define par-map (par-mapper map cons))
104 (define par-for-each (par-mapper for-each (const *unspecified*)))
106 (define (n-par-map n proc . arglists)
107 (let* ((m (make-mutex))
109 (results (make-list (length (car arglists))))
113 (for-each join-thread threads)
121 (let ((args (map car arglists))
123 (set! arglists (map cdr arglists))
124 (set! result (cdr result))
126 (set-car! my-result (apply proc args))
130 (define (n-par-for-each n proc . arglists)
131 (let ((m (make-mutex))
135 (for-each join-thread threads))
140 (if (null? (car arglists))
142 (let ((args (map car arglists)))
143 (set! arglists (map cdr arglists))
149 ;;; The following procedure is motivated by the common and important
150 ;;; case where a lot of work should be done, (not too much) in parallel,
151 ;;; but the results need to be handled serially (for example when
152 ;;; writing them to a file).
154 (define (n-for-each-par-map n s-proc p-proc . arglists)
155 "Using N parallel processes, apply S-PROC in serial order on the results
156 of applying P-PROC on ARGLISTS."
157 (let* ((m (make-mutex))
159 (no-result '(no-value))
160 (results (make-list (length (car arglists)) no-result))
164 (for-each join-thread threads))
169 (cond ((null? results)
171 ((not (eq? (car results) no-result))
172 (let ((arg (car results)))
173 ;; stop others from choosing to process results
174 (set-car! results no-result)
178 (set! results (cdr results))
184 (let ((args (map car arglists))
186 (set! arglists (map cdr arglists))
187 (set! result (cdr result))
189 (set-car! my-result (apply p-proc args))
193 (define (thread-handler tag . args)
194 (let ((n (length args))
195 (p (current-error-port)))
196 (display "In thread:" p)
208 (display "uncaught throw to " p)
215 ;;; Set system thread handler
216 (define %thread-handler thread-handler)
218 ;;; threads.scm ends here