threads.scm 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. ;;;; Copyright (C) 1996, 1998, 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
  2. ;;;;
  3. ;;;; This library is free software; you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU Lesser General Public
  5. ;;;; License as published by the Free Software Foundation; either
  6. ;;;; version 2.1 of the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This library is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;;; Lesser General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU Lesser General Public
  14. ;;;; License along with this library; if not, write to the Free Software
  15. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. ;;;;
  17. ;;;; ----------------------------------------------------------------
  18. ;;;; threads.scm -- User-level interface to Guile's thread system
  19. ;;;; 4 March 1996, Anthony Green <green@cygnus.com>
  20. ;;;; Modified 5 October 1996, MDJ <djurfeldt@nada.kth.se>
  21. ;;;; Modified 6 April 2001, ttn
  22. ;;;; ----------------------------------------------------------------
  23. ;;;;
  24. ;;; Commentary:
  25. ;; This module is documented in the Guile Reference Manual.
  26. ;; Briefly, one procedure is exported: `%thread-handler';
  27. ;; as well as four macros: `make-thread', `begin-thread',
  28. ;; `with-mutex' and `monitor'.
  29. ;;; Code:
  30. (define-module (ice-9 threads)
  31. :export (par-map
  32. par-for-each
  33. n-par-map
  34. n-par-for-each
  35. n-for-each-par-map
  36. %thread-handler)
  37. :export-syntax (begin-thread
  38. parallel
  39. letpar
  40. make-thread
  41. with-mutex
  42. monitor))
  43. (define ((par-mapper mapper) proc . arglists)
  44. (mapper join-thread
  45. (apply map
  46. (lambda args
  47. (begin-thread (apply proc args)))
  48. arglists)))
  49. (define par-map (par-mapper map))
  50. (define par-for-each (par-mapper for-each))
  51. (define (n-par-map n proc . arglists)
  52. (let* ((m (make-mutex))
  53. (threads '())
  54. (results (make-list (length (car arglists))))
  55. (result results))
  56. (do ((i 0 (+ 1 i)))
  57. ((= i n)
  58. (for-each join-thread threads)
  59. results)
  60. (set! threads
  61. (cons (begin-thread
  62. (let loop ()
  63. (lock-mutex m)
  64. (if (null? result)
  65. (unlock-mutex m)
  66. (let ((args (map car arglists))
  67. (my-result result))
  68. (set! arglists (map cdr arglists))
  69. (set! result (cdr result))
  70. (unlock-mutex m)
  71. (set-car! my-result (apply proc args))
  72. (loop)))))
  73. threads)))))
  74. (define (n-par-for-each n proc . arglists)
  75. (let ((m (make-mutex))
  76. (threads '()))
  77. (do ((i 0 (+ 1 i)))
  78. ((= i n)
  79. (for-each join-thread threads))
  80. (set! threads
  81. (cons (begin-thread
  82. (let loop ()
  83. (lock-mutex m)
  84. (if (null? (car arglists))
  85. (unlock-mutex m)
  86. (let ((args (map car arglists)))
  87. (set! arglists (map cdr arglists))
  88. (unlock-mutex m)
  89. (apply proc args)
  90. (loop)))))
  91. threads)))))
  92. ;;; The following procedure is motivated by the common and important
  93. ;;; case where a lot of work should be done, (not too much) in parallel,
  94. ;;; but the results need to be handled serially (for example when
  95. ;;; writing them to a file).
  96. ;;;
  97. (define (n-for-each-par-map n s-proc p-proc . arglists)
  98. "Using N parallel processes, apply S-PROC in serial order on the results
  99. of applying P-PROC on ARGLISTS."
  100. (let* ((m (make-mutex))
  101. (threads '())
  102. (no-result '(no-value))
  103. (results (make-list (length (car arglists)) no-result))
  104. (result results))
  105. (do ((i 0 (+ 1 i)))
  106. ((= i n)
  107. (for-each join-thread threads))
  108. (set! threads
  109. (cons (begin-thread
  110. (let loop ()
  111. (lock-mutex m)
  112. (cond ((null? results)
  113. (unlock-mutex m))
  114. ((not (eq? (car results) no-result))
  115. (let ((arg (car results)))
  116. ;; stop others from choosing to process results
  117. (set-car! results no-result)
  118. (unlock-mutex m)
  119. (s-proc arg)
  120. (lock-mutex m)
  121. (set! results (cdr results))
  122. (unlock-mutex m)
  123. (loop)))
  124. ((null? result)
  125. (unlock-mutex m))
  126. (else
  127. (let ((args (map car arglists))
  128. (my-result result))
  129. (set! arglists (map cdr arglists))
  130. (set! result (cdr result))
  131. (unlock-mutex m)
  132. (set-car! my-result (apply p-proc args))
  133. (loop))))))
  134. threads)))))
  135. (define (thread-handler tag . args)
  136. (fluid-set! the-last-stack #f)
  137. (let ((n (length args))
  138. (p (current-error-port)))
  139. (display "In thread:" p)
  140. (newline p)
  141. (if (>= n 3)
  142. (display-error #f
  143. p
  144. (car args)
  145. (cadr args)
  146. (caddr args)
  147. (if (= n 4)
  148. (cadddr args)
  149. '()))
  150. (begin
  151. (display "uncaught throw to " p)
  152. (display tag p)
  153. (display ": " p)
  154. (display args p)
  155. (newline p)))
  156. #f))
  157. ;;; Set system thread handler
  158. (define %thread-handler thread-handler)
  159. ; --- MACROS -------------------------------------------------------
  160. (define-macro (begin-thread . forms)
  161. (if (null? forms)
  162. '(begin)
  163. `(call-with-new-thread
  164. (lambda ()
  165. ,@forms)
  166. %thread-handler)))
  167. (define-macro (parallel . forms)
  168. (cond ((null? forms) '(values))
  169. ((null? (cdr forms)) (car forms))
  170. (else
  171. (let ((vars (map (lambda (f)
  172. (make-symbol "f"))
  173. forms)))
  174. `((lambda ,vars
  175. (values ,@(map (lambda (v) `(join-thread ,v)) vars)))
  176. ,@(map (lambda (form) `(begin-thread ,form)) forms))))))
  177. (define-macro (letpar bindings . body)
  178. (cond ((or (null? bindings) (null? (cdr bindings)))
  179. `(let ,bindings ,@body))
  180. (else
  181. (let ((vars (map car bindings)))
  182. `((lambda ,vars
  183. ((lambda ,vars ,@body)
  184. ,@(map (lambda (v) `(join-thread ,v)) vars)))
  185. ,@(map (lambda (b) `(begin-thread ,(cadr b))) bindings))))))
  186. (define-macro (make-thread proc . args)
  187. `(call-with-new-thread
  188. (lambda ()
  189. (,proc ,@args))
  190. %thread-handler))
  191. (define-macro (with-mutex m . body)
  192. `(dynamic-wind
  193. (lambda () (lock-mutex ,m))
  194. (lambda () (begin ,@body))
  195. (lambda () (unlock-mutex ,m))))
  196. (define-macro (monitor first . rest)
  197. `(with-mutex ,(make-mutex)
  198. (begin
  199. ,first ,@rest)))
  200. ;;; threads.scm ends here