Download presentation
Presentation is loading. Please wait.
1
A Scheme concurrency library
Takashi Kato @tk_riple
2
But Scheme has only SRFI-18
Introduction Number of CPUs are not one Using all resources requires concurrency programming But Scheme has only SRFI-18
3
The SRFI defines multithreading APIs These are very primitive
4
Example (import (rnrs) (srfi :18)) (define results '())
(define lock (make-mutex)) (define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) (define (async-fib n) (thread-start! (make-thread (lambda () (let ((r (fib n))) (mutex-lock! lock) (set! results (cons r results)) (mutex-unlock! lock) #t))))) (map thread-join! (do ((i 0 (+ i 1)) (r '() (cons (async-fib 25) r))) ((= i 1000) r)))
5
Problems Using global lock *1 If it's locked by parent thread?
Result values are globally stored *1 Creating 1000 threads *1 The example was deliberately written like that.
6
(util concurrent)*1 A library provides concurrent data structures and APIs Portable for both R6RS and R7RS Requires SRFI-18 support (and SRFI-99) Unfortunately, SRFI-18 isn‘t widely supported… repository:
7
Shared queue Queue with atomic operations
Retrieving an element from empty queue would wait Get (2) Put (3) Block! Block! Shared Queue Element Element Block! Put (1) Get (4)
8
Using shared queue (import (rnrs) (srfi :18) (util concurrent))
(define results (make-shared-queue)) (define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) (define (async-fib n) (thread-start! (make-thread (lambda () (shared-queue-put! results (fib n)) #t)))) (define threads (do ((i 0 (+ i 1)) (r '() (cons (async-fib 25) r))) ((= i 1000) r))) (do ((i 0 (+ i 1))) ((= i 1000)) (shared-queue-get! results)) (map thread-join! threads)
9
Thread pool Thread creation might be expensive Resources are finite
On Windows, 2000 thread would be the limit Reusing existing thread resolves the issues
10
Usual thread pool Queue Job Job Job Job Thread 1 Thread 2 Thread n
11
Our thread pool Queue Job Job Thread 1 Pool Queue Job Job Container
Thread n
12
Thread pool (2) Each managed thread has own channel
To avoid abondant mutex Thread pool check the least busy thread Managed threads tell their availability to the pool To make best case thread choosing O(1)
13
Using thread pool (import (rnrs) (srfi :18) (util concurrent))
(define results (make-shared-queue)) (define thread-pool (make-thread-pool 100)) (define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) (define (async-fib n) (lambda () (shared-queue-put! results (fib n)) #t)) (do ((i 0 (+ i 1))) ((= i 1000)) (thread-pool-push-task! thread-pool (async-fib 25))) (do ((i 0 (+ i 1))) ((= i 1000)) (shared-queue-get! results)) ;; Cannot retrieve execution result
14
Future and Executor Thread pool can't retrieve execution result
Future is a task to be executed by executor Executor executes futures After the execution, users can retrieve the results from futures
15
Using future and executor
(import (rnrs) (srfi :18) (util concurrent)) (define results (make-shared-queue)) (define executor (make-thread-pool-executor 100 push-future-handler)) (define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) (define (async-fib n) (lambda () (shared-queue-put! results (fib n)) #t)) (define futures (do ((i 0 (+ i 1)) (r '() (cons (executor-submit! executor (async-fib 25)) r))) ((= i 1000) r))) (do ((i 0 (+ i 1))) ((= i 1000)) (shared-queue-get! results)) (map future-get futures)
16
Conclusion Using the library reduces: Explicit locks
Explicit thread creation Resource management This means: Less dead lock Better stability
17
Questions?
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.