Thread- and exception aware, lazy-looking synchronization with timeouts - extending srfi-45.
Force and delay from CHICKEN core as well as SRFI-45 exhibit unintuitive behavior in the presence of SRFI-18 threads and when exceptions are raised. The srfi-45 egg extends the srfi-45 reference implementation to support multiple values but is still unintuitive wrt. threads and exceptions.
This egg builds and extends those, explicit aiming on the following objectives:
- Explicit support for multiple value returns from suspended expressions.
- Aware of threads and exception handling. Multiple threads forceing the same promise do NOT cause multiple evaluation of the delayed (or lazy) expression. The same thread may still recurse into the promise being forced.
- Bounded space as in srfi-45.
- Extends force with optional parameters to simplify exception handling.
- Futures are syntactically similar to delay but evaluated in another SRFI-18 thread.
- Cheap timeouts.
- Adds single use "awaitable" values (expectable).
- Does NOT supplement CHICKEN's force/delay but replaces it. (To reduce confusion for developers. Supplementing them as the srfi-45 egg does had caused too many confusion for the author of this egg at least.)
The implementation of expectable currently (2016-01-10) depends on a CHICKEN having the fix for Ticket 1231 applied.
Timeouts come at negligible runtime overhead – the cost of being coarse grained. It is assumed that most timeouts never "fire" hence the are deferred for the sake of optimization. Timeouts fire only if they are not canceled before at least a full timeout-period passed. A timeout-period defaults to one second.
- (timeout-condition? x) -> boolean procedure
Test x to be a timeout condition object.
- (eager . vals) -> PROMISE procedure
Returns a promise which, when forced returns the values vals.
- (lazy EXPRESSION) -> PROMISE syntax
Returns a promise for EXPRESSION.
- (delay EXPRESSION) -> PROMISE syntax
Returns a promise, a delayed evaluation of EXPRESSION.
- (delay/timeout TIMEOUT EXPRESSION) -> PROMISE syntax
Same as delay EXPRESSION. Promise may fail raising an object for which timeout-condition? returns #t.
- (future EXPRESSION) -> PROMISE syntax
Returns a promise, a delayed evaluation of EXPRESSION. The evaluation of expression is started immediately in another thread. PROMISE will cache exceptions returned by EXPRSSION.
- (future/timeout TIMEOUT EXPRESSION) -> PROMISE syntax
Variation of future. The evaluation of EXPRESSION receives an exceptions for which timeout-condition? holds after TIMEOUT.
- (order EXPRESSION) -> PROMISE syntax
Returns a promise, a delayed evaluation of EXPRESSION. The evaluation of expression is ordered from another thread in a threadpool. PROMISE will cache exceptions returned by EXPRSSION.
- (order/timeout TIMEOUT EXPRESSION) -> PROMISE syntax
Variation of order. The evaluation of EXPRESSION receives an exceptions for which timeout-condition? holds after TIMEOUT.
- (lazy-future EXPRESSION) -> PROMISE syntax
Same as future however the thread is NOT started. Use demand to start it prior to force. Use of force will also start it if not demanded before.
- (demand PROMISE) -> boolean procedure
If the PROMISE was created by lazy-future and the thread is not yet started, start it. Returns #t if the thread was started only now, otherwise returns #f.
- (force OBJECT [FAIL]) -> . * procedure
Force OBJECT. Returns OBJECT if it is NOT a promise. Otherwise returns the values the suspended EXPRESSION returned.
If FAIL is provided it must be a procedure of one argument. Exceptions raised from the EXPRESSION are passed to FAIL.
This is equivalent to (but more efficiently implemented)
(handle-exceptions ex (FAIL ex) (force OBJECT))
- (expectable [NAME] [THUNK]) -> PROCEDURE PROMISE procedure
NAME is any object and used for debug purposes only (currently passed as name of an internal mutex). Returns two values. PROCEDURE takes a flag indicating whether the PROMISE shall return successful (if #t) or fail and values to return from forceing the PROMISE. If the flag is #f only the first of those values is used and passed to the exception handler as the exception raised from the PROMISE.
When THUNK is given the resulting promise behaves like a promise created by lazy.
- (fulfil! PROMISE TYPE . ARGS) -> boolean procedure
Mutate PROMISE to be fulfilled. TYPE must be a boolean. If #t the PROMISE is set to return successfully the values ARGS. If TYPE is #f the PROMISE will raise the first value of ARGS as exception.
Note: This procedure MAY be removed in future versions (if it proves to be questionable).
Latest version: forcible from askemos.org
0.3: Added /timeout.
0.2: Added optional THUNK to expectable.
0.1: Initial version.
Jörg F. Wittenberger
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ASIS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.