Created
December 16, 2018 16:48
-
-
Save soegaard/d32e12d89705c774b71ee78ef930a4bf to your computer and use it in GitHub Desktop.
Concurrency primitives for SICP for Racket 7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#lang racket | |
;; adapted from: | |
;; https://planet.racket-lang.org/package-source/dyoo/sicp-concurrency.plt/1/2/sicp-concurrency.ss | |
;; concurrency: SICP concurrency primitives | |
;; adapted from http://list.cs.brown.edu/pipermail/plt-scheme/2002-September/000620.html | |
;;; Sources: | |
;;; Dorai Sitaram, "Learn Scheme in a Fixnum of Dayes", chapter 15 | |
;;; Dyvig, http://www.scheme.com/tspl2d/examples.html#g2433 | |
(define (thunk? datum) | |
(and (procedure? datum) | |
(procedure-arity-includes? datum 0))) | |
(struct cell (val) #:mutable #:extra-constructor-name make-cell) | |
(provide (rename-out [timed-datum #%datum] | |
[timed-apply #%app] | |
[timed-set! set!]) | |
(all-defined-out)) | |
(define yield-handler (lambda () (void))) | |
(define clock 0) | |
(define (start-timer ticks new-handler) | |
(set! yield-handler new-handler) | |
(set! clock ticks)) | |
(define (stop-timer) | |
(let ([time-left clock]) | |
(set! clock 0) | |
time-left)) | |
(define (decrement-timer) | |
(when (> clock 0) | |
(begin | |
(set! clock (- clock 1)) | |
(when (= clock 0) | |
(yield-handler))))) | |
(define (random-shuffle a-list) | |
(map cdr | |
(sort (map (lambda (x) (cons (random) x)) a-list) | |
(lambda (x y) (< (car x) (car y)))))) | |
(define (parallel-execute . thunks) | |
(round-robin (map make-engine (random-shuffle thunks)))) | |
(define (dole-out-gas) | |
(add1 (random 12))) | |
(define (round-robin engs) | |
(if (null? engs) | |
'() | |
((car engs) (dole-out-gas) | |
(lambda (ticks value) | |
(cons value (round-robin (cdr engs)))) | |
(lambda (eng) | |
(round-robin | |
(append (cdr engs) (list eng))))))) | |
(define make-engine | |
(let ([do-complete #f] | |
[do-expire #f]) | |
(define (timer-handler) | |
(start-timer (call/cc do-expire) timer-handler)) | |
(define (new-engine resume) | |
(lambda (ticks complete expire) | |
((call/cc (lambda (escape) | |
(set! do-complete | |
(lambda (ticks value) | |
(escape (lambda () (complete ticks value))))) | |
(set! do-expire | |
(lambda (resume) | |
(escape (lambda () (expire (new-engine resume)))))) | |
(resume ticks)))))) | |
(lambda (proc) | |
(new-engine | |
(lambda (ticks) | |
(start-timer ticks timer-handler) | |
(let ((value (proc))) | |
(let ((ticks (stop-timer))) | |
(do-complete ticks value)))))))) | |
(define-syntax timed-datum | |
(syntax-rules () | |
[(_ . datum) | |
(begin | |
(decrement-timer) | |
(#%datum . datum))])) | |
(define-syntax timed-apply | |
(syntax-rules () | |
((_ operator rand ...) | |
(begin | |
(decrement-timer) | |
(#%app (begin (decrement-timer) operator) | |
(begin (decrement-timer) rand) ...))))) | |
(define-syntax timed-set! | |
(syntax-rules () | |
((_ id expr) | |
(begin | |
(decrement-timer) | |
(set! id (begin | |
(let ([val expr]) | |
(decrement-timer) | |
val))))))) | |
;; The following definitions are adapted from SICP | |
;; | |
;; http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-23.html#call_footnote_Temp_430 | |
(define (make-serializer) | |
(let ((mutex (timed-apply make-mutex))) | |
(lambda (p) | |
(define (serialized-p . args) | |
(timed-apply mutex 'acquire) | |
(let ((val (timed-apply apply p args))) | |
(timed-apply mutex 'release) | |
val)) | |
serialized-p))) | |
(define (make-mutex) | |
(let ((cell (timed-apply make-cell #f))) | |
(define (the-mutex m) | |
(cond ((timed-apply eq? m 'acquire) | |
(when (timed-apply test-and-set! cell) | |
(timed-apply the-mutex 'acquire))) | |
((timed-apply eq? m 'release) | |
(timed-apply clear! cell)))) | |
the-mutex)) | |
(define (clear! cell) | |
(timed-apply set-cell-val! cell #f)) | |
(define (test-and-set! cell) | |
(if (cell-val cell) | |
#t | |
(begin (set-cell-val! cell #t) | |
#f))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment