threads.scm 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. ;;;; Copyright (C) 1996, 1998, 2001, 2002, 2003, 2006, 2010, 2011 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 3 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. #:use-module (ice-9 futures)
  32. #:export (begin-thread
  33. parallel
  34. letpar
  35. make-thread
  36. with-mutex
  37. monitor
  38. par-map
  39. par-for-each
  40. n-par-map
  41. n-par-for-each
  42. n-for-each-par-map
  43. %thread-handler))
  44. ;;; Macros first, so that the procedures expand correctly.
  45. (define-syntax-rule (begin-thread e0 e1 ...)
  46. (call-with-new-thread
  47. (lambda () e0 e1 ...)
  48. %thread-handler))
  49. (define-syntax parallel
  50. (lambda (x)
  51. (syntax-case x ()
  52. ((_ e0 ...)
  53. (with-syntax (((tmp0 ...) (generate-temporaries (syntax (e0 ...)))))
  54. #'(let ((tmp0 (future e0))
  55. ...)
  56. (values (touch tmp0) ...)))))))
  57. (define-syntax-rule (letpar ((v e) ...) b0 b1 ...)
  58. (call-with-values
  59. (lambda () (parallel e ...))
  60. (lambda (v ...)
  61. b0 b1 ...)))
  62. (define-syntax-rule (make-thread proc arg ...)
  63. (call-with-new-thread
  64. (lambda () (proc arg ...))
  65. %thread-handler))
  66. (define-syntax-rule (with-mutex m e0 e1 ...)
  67. (let ((x m))
  68. (dynamic-wind
  69. (lambda () (lock-mutex x))
  70. (lambda () (begin e0 e1 ...))
  71. (lambda () (unlock-mutex x)))))
  72. (define-syntax-rule (monitor first rest ...)
  73. (with-mutex (make-mutex)
  74. first rest ...))
  75. (define (par-mapper mapper)
  76. (lambda (proc . arglists)
  77. (mapper touch
  78. (apply map
  79. (lambda args
  80. (future (apply proc args)))
  81. arglists))))
  82. (define par-map (par-mapper map))
  83. (define par-for-each (par-mapper for-each))
  84. (define (n-par-map n proc . arglists)
  85. (let* ((m (make-mutex))
  86. (threads '())
  87. (results (make-list (length (car arglists))))
  88. (result results))
  89. (do ((i 0 (+ 1 i)))
  90. ((= i n)
  91. (for-each join-thread threads)
  92. results)
  93. (set! threads
  94. (cons (begin-thread
  95. (let loop ()
  96. (lock-mutex m)
  97. (if (null? result)
  98. (unlock-mutex m)
  99. (let ((args (map car arglists))
  100. (my-result result))
  101. (set! arglists (map cdr arglists))
  102. (set! result (cdr result))
  103. (unlock-mutex m)
  104. (set-car! my-result (apply proc args))
  105. (loop)))))
  106. threads)))))
  107. (define (n-par-for-each n proc . arglists)
  108. (let ((m (make-mutex))
  109. (threads '()))
  110. (do ((i 0 (+ 1 i)))
  111. ((= i n)
  112. (for-each join-thread threads))
  113. (set! threads
  114. (cons (begin-thread
  115. (let loop ()
  116. (lock-mutex m)
  117. (if (null? (car arglists))
  118. (unlock-mutex m)
  119. (let ((args (map car arglists)))
  120. (set! arglists (map cdr arglists))
  121. (unlock-mutex m)
  122. (apply proc args)
  123. (loop)))))
  124. threads)))))
  125. ;;; The following procedure is motivated by the common and important
  126. ;;; case where a lot of work should be done, (not too much) in parallel,
  127. ;;; but the results need to be handled serially (for example when
  128. ;;; writing them to a file).
  129. ;;;
  130. (define (n-for-each-par-map n s-proc p-proc . arglists)
  131. "Using N parallel processes, apply S-PROC in serial order on the results
  132. of applying P-PROC on ARGLISTS."
  133. (let* ((m (make-mutex))
  134. (threads '())
  135. (no-result '(no-value))
  136. (results (make-list (length (car arglists)) no-result))
  137. (result results))
  138. (do ((i 0 (+ 1 i)))
  139. ((= i n)
  140. (for-each join-thread threads))
  141. (set! threads
  142. (cons (begin-thread
  143. (let loop ()
  144. (lock-mutex m)
  145. (cond ((null? results)
  146. (unlock-mutex m))
  147. ((not (eq? (car results) no-result))
  148. (let ((arg (car results)))
  149. ;; stop others from choosing to process results
  150. (set-car! results no-result)
  151. (unlock-mutex m)
  152. (s-proc arg)
  153. (lock-mutex m)
  154. (set! results (cdr results))
  155. (unlock-mutex m)
  156. (loop)))
  157. ((null? result)
  158. (unlock-mutex m))
  159. (else
  160. (let ((args (map car arglists))
  161. (my-result result))
  162. (set! arglists (map cdr arglists))
  163. (set! result (cdr result))
  164. (unlock-mutex m)
  165. (set-car! my-result (apply p-proc args))
  166. (loop))))))
  167. threads)))))
  168. (define (thread-handler tag . args)
  169. (let ((n (length args))
  170. (p (current-error-port)))
  171. (display "In thread:" p)
  172. (newline p)
  173. (if (>= n 3)
  174. (display-error #f
  175. p
  176. (car args)
  177. (cadr args)
  178. (caddr args)
  179. (if (= n 4)
  180. (cadddr args)
  181. '()))
  182. (begin
  183. (display "uncaught throw to " p)
  184. (display tag p)
  185. (display ": " p)
  186. (display args p)
  187. (newline p)))
  188. #f))
  189. ;;; Set system thread handler
  190. (define %thread-handler thread-handler)
  191. ;;; threads.scm ends here