Next: Introduction, Previous: (dir), Up: (dir) [Contents][Index]
This is the green-threads Reference Manual, version 0.3, generated automatically by Declt version 3.0 "Montgomery Scott" on Tue Dec 22 13:38:17 2020 GMT+0.
• Introduction | What green-threads is all about | |
• Systems | The systems documentation | |
• Modules | The modules documentation | |
• Files | The files documentation | |
• Packages | The packages documentation | |
• Definitions | The symbols documentation | |
• Indexes | Concepts, functions, variables and data types |
A lightweight thread / cooperative multitasking library for Common Lisp.
Allows for cooperative multitasking with help of CL-CONT for continuations. Tries to mimic BORDEAUX-THREADS API as much as possible.
Let's show how the threads work and build up to higher level abstractions.
The MAKE-THREAD function takes a closure/function of zero arguments and starts executing it, since we are not using OS threads, it cannot actually preempt the thread, so the thread has to yield by calling QUEUE-NEXT, passing a closure containing the continuation of the thread and return. MAKE-THREAD has an optional keyword parameter :NAME for specifying a name for the thread.
In this example, we create a thread which executes immediately, it creates an additional thread and then continues on, it yields by calling QUEUE-NEXT and passing a continuation. That allows the other thread to execute before continuing the first:
(use-package :green-threads)
(make-thread
(lambda ()
(format t "Do Something~%")
(make-thread
(lambda ()
(format t "Do Something Else.~%")))
(queue-next ;; queue next action and yield
(lambda ()
(format t "Do More.~%")))))
;; output:
;; Do Something
;; Do Something Else.
;; Do More.
In the above example, the continuation of the primary thread is nested inside a QUEUE-NEXT call. That's pretty inconvenient. Nobody enjoys programming in continuation-passing-style (CPS), so let's see how we can avoid that.
In the next example, we use the CL-CONT library directly to transform our code into CPS which allows us to use THREAD-YIELD to yield without having to specify the continuation ourselves. You'll notice that the primary thread no longer has to nest the continuation in a closure.
(make-thread
(cl-cont:with-call/cc
(lambda ()
(format t "Do Something~%")
(cl-cont:without-call/cc
(make-thread
(cl-cont:with-call/cc
(lambda ()
(format t "Do Something Else~%")))))
(thread-yield) ;; allow other threads to run
(format t "Do More~%"))))
The last example is a bit noisy with the CL-CONT calls, so we can instead use the WITH-GREEN-THREAD macro which wraps our code in an anonymous closure, and applies CL-CONT macros appropriately.
(with-green-thread
(format t "Do Something~%")
(with-green-thread
(format t "Do Something Else~%"))
(thread-yield) ;; allow other threads to run
(format t "Do More~%"))
Viola, you can now write cooperatively multitasking code without resorting to writing CPS by hand.
Dynamic bindings don't over well into green threads, so this library has a similar mechanism as BORDEAUX-THREADS, and that is the *DEFAULT-SPECIAL-BINDINGS* special variable which can be set to an alist of symbol/value pairs that will be specially bound in any green threads you create.
(defparameter *foo* "outer")
(with-green-thread
(print *foo*)
(let ((*default-special-bindings* '((*foo* . "first"))))
(with-green-thread
(print *foo*)))
(thread-yield)
(print *foo*))
;; output:
;; "outer"
;; "first"
;; "outer"
MAKE-THREAD creates a new green thread and runs it if no green threads are currently running. If called from within a running green thread, it will queue the thread to run later.
CURRENT-THREAD returns the currently running thread object or NIL if you are not currently in one.
THREADP returns T if the object passed to it is a thread object.
THREAD-NAME returns the name of the thread passed to it or NIL of none was provided.
ALL-THREADS returns a list of all threads.
DESTROY-THREAD will do just that, cannot be called on currently executing thread.
THREAD-ALIVE-P returns T if thread passed to it is still alive.
JOIN-THREAD (thread) Requires CL-CONT:WITH-CALL/CC environment, causes the current thread to wait for the other thread to complete before continuing.
MAKE-FUTURE () creates a future object.
QUEUE-FUTURE (future action &optional thread) queues an action on current (or specified) thread to take place when provided future is completed.
FINISH (future &rest values) signals that a future is complete and provides return values for the future.
FUTURE-FINISHED-P (future) T if future has already had COMPLETE-FUTURE called on it.
FUTURE-VALUES (future) Returns the values given to the future when it was completed.
WAIT-ON (future) Requires CL-CONT:WITH-CALL/CC environment, causes the current thread to wait for the completion of the specified future and returns the values given to the future when it was completed.
GET-JOIN-FUTURE (thread) Returns a future which will complete when the passed in thread completes. This provides a lower level way to join threads without using JOIN-THREAD which requires CL-CONT:WITH-CALL/CC.
Example use of futures from (taken from tests):
(defparameter *future-one* (make-future))
(defparameter *val1* nil)
(defparameter *val2* nil)
;; WAIT-FOR test
(with-green-thread
(multiple-value-bind (v1 v2) (wait-for *future-one*)
(setf *val1* v1)
(setf *val2* v2)))
(is *val1* nil)
(is *val2* nil)
(is (future-complete-p *future-one*) nil)
(complete-future *future-one* :foo :bar)
(is *val1* :foo)
(is *val2* :bar)
(is (future-complete-p *future-one*) T)
Inspired by sykopomp's ChanL, which relies on BORDEAUX-THREADS, I've added basic unbuffered channel support.
(make-instance 'CHANNEL) creates a new channel.
SEND/CC (channel value &key blockp) Requires CL-CONT:WITH-CALL/CC environment. Sends a value to a channel, and blocks, unless blockp is nil. Returns the channel that received the value unless blockp is nil and there is no thread waiting to receive in which case it returns nil.
RECV/CC (channel &key blockp) Requires CL-CONT:WITH-CALL/CC environment. Receives a value from a channel, and blocks, unless blockp is nil. Returns 2 values, the first is the value being received and the second is a generalized boolean that is only nil if blockp is nil and there is no thread waiting to send a value.
SEND (channel value continuation &key blockp) Just like SEND/CC but doesn't require CL-CONT, you just have to pass in the continuation manually. CPS is fun. Instead of returning the channel that receives the message, it (or nil) is passed to continuation.
RECV (channel continuation &key blockp) Just like RECV/CC but doesn't require CL-CONT, you just have to pass in the continuation manually. CPS is fun. Instead of returning the 2 values, the continuation is called with them.
Behold, the venerable sieve of Eratosthenes:
(ql:quickload :green-threads)
(cl-cont:defun/cc counter (end chan)
(loop for i from 2 to end
do (gt:send/cc chan i)))
(declaim (ftype function filter)) ;; unnecessary, silence warnings
(cl-cont:defun/cc filter (listen)
(let ((prime (gt:recv/cc listen)))
(format t "~a " prime)
(let ((chan (make-instance 'gt:channel)))
(gt:with-green-thread
(filter chan))
(loop
(let ((i (gt:recv/cc listen)))
(if (> (mod i prime) 0)
(gt:send/cc chan i)))))))
(gt:with-green-thread
(let ((count (make-instance 'gt:channel)))
(gt:with-green-thread
(counter 100 count))
(gt:with-green-thread
(filter count))))
Clone repo into ~/quicklisp/local-projects. Run the following command:
(ql:quickload :green-threads)
100% test coverage.
Copyright (c) 2012 Stephen A. Goss (steveth45@gmail.com)
Licensed under the Modified BSD License.
Next: Modules, Previous: Introduction, Up: Top [Contents][Index]
The main system appears first, followed by any subsystem dependency.
• The green-threads system |
Stephen A. Goss
Modified BSD
A lightweight threading / cooperative multitasking library.
# Green-Threads
A lightweight thread / cooperative multitasking library for Common Lisp.
## Usage
Allows for cooperative multitasking with help of CL-CONT for continuations. Tries to mimic BORDEAUX-THREADS API as much as possible.
Let’s show how the threads work and build up to higher level
abstractions.
The MAKE-THREAD function takes a closure/function of zero arguments and
starts executing it, since we are not using OS threads, it cannot
actually preempt the thread, so the thread has to yield by calling
QUEUE-NEXT, passing a closure containing the continuation of the thread
and return. MAKE-THREAD has an optional keyword parameter :NAME for
specifying a name for the thread.
In this example, we create a thread which executes immediately, it
creates an additional thread and then continues on, it yields by calling
QUEUE-NEXT and passing a continuation. That allows the other thread to
execute before continuing the first:
“‘common-lisp
(use-package :green-threads)
(make-thread
(lambda ()
(format t "Do Something~%")
(make-thread
(lambda ()
(format t "Do Something Else.~%")))
(queue-next ;; queue next action and yield
(lambda ()
(format t "Do More.~%")))))
;; output:
;; Do Something
;; Do Something Else.
;; Do More.
“‘
In the above example, the continuation of the primary thread is nested
inside a QUEUE-NEXT call. That’s pretty inconvenient. Nobody enjoys
programming in continuation-passing-style (CPS), so let’s see how we can
avoid that.
In the next example, we use the CL-CONT library directly to transform
our code into CPS which allows us to use THREAD-YIELD to yield without
having to specify the continuation ourselves. You’ll notice that the
primary thread no longer has to nest the continuation in a closure.
“‘common-lisp
(make-thread
(cl-cont:with-call/cc
(lambda ()
(format t "Do Something~%")
(cl-cont:without-call/cc
(make-thread
(cl-cont:with-call/cc
(lambda ()
(format t "Do Something Else~%")))))
(thread-yield) ;; allow other threads to run
(format t "Do More~%"))))
“‘
The last example is a bit noisy with the CL-CONT calls, so we can
instead use the WITH-GREEN-THREAD macro which wraps our code in an
anonymous closure, and applies CL-CONT macros appropriately.
“‘common-lisp
(with-green-thread
(format t "Do Something~%")
(with-green-thread
(format t "Do Something Else~%"))
(thread-yield) ;; allow other threads to run
(format t "Do More~%"))
“‘
Viola, you can now write cooperatively multitasking code without
resorting to writing CPS by hand.
Dynamic bindings don’t over well into green threads, so this library has
a similar mechanism as BORDEAUX-THREADS, and that is the
\*DEFAULT-SPECIAL-BINDINGS\* special variable which can be set to an
alist of symbol/value pairs that will be specially bound in any green
threads you create.
“‘common-lisp
(defparameter *foo* "outer")
(with-green-thread
(print *foo*)
(let ((*default-special-bindings* ’((*foo* . "first"))))
(with-green-thread
(print *foo*)))
(thread-yield)
(print *foo*))
;; output:
;; "outer"
;; "first"
;; "outer"
“‘
MAKE-THREAD creates a new green thread and runs it if no green threads
are currently running. If called from within a running green thread, it
will queue the thread to run later.
CURRENT-THREAD returns the currently running thread object or NIL if you
are not currently in one.
THREADP returns T if the object passed to it is a thread object.
THREAD-NAME returns the name of the thread passed to it or NIL of none
was provided.
ALL-THREADS returns a list of all threads.
DESTROY-THREAD will do just that, cannot be called on currently
executing thread.
THREAD-ALIVE-P returns T if thread passed to it is still alive.
JOIN-THREAD (thread) Requires CL-CONT:WITH-CALL/CC environment, causes
the current thread to wait for the other thread to complete before
continuing.
### Futures
MAKE-FUTURE () creates a future object.
QUEUE-FUTURE (future action &optional thread) queues an action on
current (or specified) thread to take place when provided future is
completed.
FINISH (future &rest values) signals that a future is complete
and provides return values for the future.
FUTURE-FINISHED-P (future) T if future has already had COMPLETE-FUTURE
called on it.
FUTURE-VALUES (future) Returns the values given to the future when it
was completed.
WAIT-ON (future) Requires CL-CONT:WITH-CALL/CC environment, causes the
current thread to wait for the completion of the specified future and
returns the values given to the future when it was completed.
GET-JOIN-FUTURE (thread) Returns a future which will complete when the passed in thread completes. This provides a lower level way to join threads without using JOIN-THREAD which requires CL-CONT:WITH-CALL/CC.
Example use of futures from (taken from tests):
“‘common-lisp
(defparameter *future-one* (make-future))
(defparameter *val1* nil)
(defparameter *val2* nil)
;; WAIT-FOR test
(with-green-thread
(multiple-value-bind (v1 v2) (wait-for *future-one*)
(setf *val1* v1)
(setf *val2* v2)))
(is *val1* nil)
(is *val2* nil)
(is (future-complete-p *future-one*) nil)
(complete-future *future-one* :foo :bar)
(is *val1* :foo)
(is *val2* :bar)
(is (future-complete-p *future-one*) T)
“‘
### Channels
Inspired by sykopomp’s [ChanL](https://github.com/sykopomp/chanl), which relies on BORDEAUX-THREADS, I’ve added basic unbuffered channel support.
(make-instance ’CHANNEL) creates a new channel.
SEND/CC (channel value &key blockp) Requires CL-CONT:WITH-CALL/CC environment. Sends a value to a channel, and blocks, unless blockp is nil. Returns the channel that received the value unless blockp is nil and there is no thread waiting to receive in which case it returns nil.
RECV/CC (channel &key blockp) Requires CL-CONT:WITH-CALL/CC environment.
Receives a value from a channel, and blocks, unless blockp is nil.
Returns 2 values, the first is the value being received and the second
is a generalized boolean that is only nil if blockp is nil and there is
no thread waiting to send a value.
SEND (channel value continuation &key blockp) Just like SEND/CC but
doesn’t require CL-CONT, you just have to pass in the continuation
manually. CPS is fun. Instead of returning the channel that receives the
message, it (or nil) is passed to continuation.
RECV (channel continuation &key blockp) Just like RECV/CC but doesn’t
require CL-CONT, you just have to pass in the continuation manually.
CPS is fun. Instead of returning the 2 values, the continuation is
called with them.
Behold, the venerable sieve of Eratosthenes:
“‘common-lisp
(ql:quickload :green-threads)
(cl-cont:defun/cc counter (end chan)
(loop for i from 2 to end
do (gt:send/cc chan i)))
(declaim (ftype function filter)) ;; unnecessary, silence warnings
(cl-cont:defun/cc filter (listen)
(let ((prime (gt:recv/cc listen)))
(format t "~a " prime)
(let ((chan (make-instance ’gt:channel)))
(gt:with-green-thread
(filter chan))
(loop
(let ((i (gt:recv/cc listen)))
(if (> (mod i prime) 0)
(gt:send/cc chan i)))))))
(gt:with-green-thread
(let ((count (make-instance ’gt:channel)))
(gt:with-green-thread
(counter 100 count))
(gt:with-green-thread
(filter count))))
“‘
## Installation
Clone repo into ~/quicklisp/local-projects. Run the following command:
“‘common-lisp
(ql:quickload :green-threads)
“‘
## TODO
100% test coverage.
## Author
* Stephen A. Goss (steveth45@gmail.com)
## Copyright
Copyright (c) 2012 Stephen A. Goss (steveth45@gmail.com)
# License
Licensed under the Modified BSD License.
0.3
green-threads.asd (file)
src (module)
Modules are listed depth-first from the system components tree.
• The green-threads/src module |
green-threads (system)
src/
green-threads.lisp (file)
Files are sorted by type and then listed depth-first from the systems components trees.
• Lisp files |
• The green-threads.asd file | ||
• The green-threads/src/green-threads.lisp file |
Next: The green-threads/src/green-threads․lisp file, Previous: Lisp files, Up: Lisp files [Contents][Index]
green-threads.asd
green-threads (system)
Previous: The green-threads․asd file, Up: Lisp files [Contents][Index]
src (module)
src/green-threads.lisp
Next: Definitions, Previous: Files, Up: Top [Contents][Index]
Packages are listed by definition order.
• The green-threads-asd package | ||
• The green-threads package |
Next: The green-threads package, Previous: Packages, Up: Packages [Contents][Index]
green-threads.asd
Previous: The green-threads-asd package, Up: Packages [Contents][Index]
green-threads.lisp (file)
gt
Definitions are sorted by export status, category, package, and then by lexicographic order.
• Exported definitions | ||
• Internal definitions |
Next: Internal definitions, Previous: Definitions, Up: Definitions [Contents][Index]
• Exported special variables | ||
• Exported macros | ||
• Exported functions | ||
• Exported generic functions | ||
• Exported classes |
Next: Exported macros, Previous: Exported definitions, Up: Exported definitions [Contents][Index]
green-threads.lisp (file)
Next: Exported functions, Previous: Exported special variables, Up: Exported definitions [Contents][Index]
A convenience macro that runs the code in a lambda wrapped in CPS transformin macros and a call to make-thread. Returns thread object.
green-threads.lisp (file)
Next: Exported generic functions, Previous: Exported macros, Up: Exported definitions [Contents][Index]
Returns a list of all active threads, which are threads that have been created but not destroyed or finished.
green-threads.lisp (file)
Returns the currently running greed thread or NIL if not called from within thread.
green-threads.lisp (file)
Destroys the thread passed in, so it will not run any more. It is an error to call this on the current thread.
green-threads.lisp (file)
Returns the values given to the future when it was completed.
green-threads.lisp (file)
Gets a future object from thread which will be completed when the thread is finished.
green-threads.lisp (file)
/home/quickref/quicklisp/dists/quicklisp/software/cl-cont-20110219-darcs/src/special-transformers.lisp
Create a new green thread with an optional :name. The first parameter should be a function that takes no arguments. The thread will be queued immediately, so will run immediately if make-thread is called from outside any other green threads. Returns a thread object.
green-threads.lisp (file)
Queues an action on current (or specified) thread to take place when provided future is completed.
green-threads.lisp (file)
green-threads.lisp (file)
/home/quickref/quicklisp/dists/quicklisp/software/cl-cont-20110219-darcs/src/special-transformers.lisp
/home/quickref/quicklisp/dists/quicklisp/software/cl-cont-20110219-darcs/src/special-transformers.lisp
Returns T if the passed in thread has not been destroyed.
green-threads.lisp (file)
Returns the name of the thread given at the time of creation or NIL.
green-threads.lisp (file)
/home/quickref/quicklisp/dists/quicklisp/software/cl-cont-20110219-darcs/src/special-transformers.lisp
Returns T if the object passed in is a thread.
green-threads.lisp (file)
/home/quickref/quicklisp/dists/quicklisp/software/cl-cont-20110219-darcs/src/special-transformers.lisp
Next: Exported classes, Previous: Exported functions, Up: Exported definitions [Contents][Index]
green-threads.lisp (file)
green-threads.lisp (file)
Previous: Exported generic functions, Up: Exported definitions [Contents][Index]
green-threads.lisp (file)
standard-object (class)
(make-instance (quote green-threads::batched-queue))
(make-instance (quote green-threads::batched-queue))
Previous: Exported definitions, Up: Definitions [Contents][Index]
• Internal special variables | ||
• Internal functions | ||
• Internal generic functions | ||
• Internal classes |
Next: Internal functions, Previous: Internal definitions, Up: Internal definitions [Contents][Index]
green-threads.lisp (file)
green-threads.lisp (file)
green-threads.lisp (file)
Next: Internal generic functions, Previous: Internal special variables, Up: Internal definitions [Contents][Index]
green-threads.lisp (file)
green-threads.lisp (file)
green-threads.lisp (file)
green-threads.lisp (file)
Next: Internal classes, Previous: Internal functions, Up: Internal definitions [Contents][Index]
automatically generated reader method
green-threads.lisp (file)
automatically generated writer method
green-threads.lisp (file)
automatically generated reader method
green-threads.lisp (file)
automatically generated reader method
green-threads.lisp (file)
green-threads.lisp (file)
green-threads.lisp (file)
automatically generated reader method
green-threads.lisp (file)
automatically generated reader method
green-threads.lisp (file)
automatically generated reader method
green-threads.lisp (file)
automatically generated writer method
green-threads.lisp (file)
green-threads.lisp (file)
green-threads.lisp (file)
green-threads.lisp (file)
Previous: Internal generic functions, Up: Internal definitions [Contents][Index]
green-threads.lisp (file)
standard-object (class)
:front
:rear
green-threads.lisp (file)
standard-object (class)
:name
name (generic function)
:binding-symbols
binding-symbols (generic function)
:binding-values
binding-values (generic function)
next-action (generic function)
(setf next-action) (generic function)
t
alive (generic function)
(setf alive) (generic function)
(cl-async-future:make-future)
join-future (generic function)
Previous: Definitions, Up: Top [Contents][Index]
• Concept index | ||
• Function index | ||
• Variable index | ||
• Data type index |
Next: Function index, Previous: Indexes, Up: Indexes [Contents][Index]
Jump to: | F G L M |
---|
Jump to: | F G L M |
---|
Next: Variable index, Previous: Concept index, Up: Indexes [Contents][Index]
Jump to: | (
A B C D E F G H J M N Q R S T W |
---|
Jump to: | (
A B C D E F G H J M N Q R S T W |
---|
Next: Data type index, Previous: Function index, Up: Indexes [Contents][Index]
Jump to: | *
A B F J N R S W |
---|
Jump to: | *
A B F J N R S W |
---|
Previous: Variable index, Up: Indexes [Contents][Index]
Jump to: | B C G P S T |
---|
Jump to: | B C G P S T |
---|