diff options
author | Andy Wingo <wingo@pobox.com> | 2017-03-07 20:57:59 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2017-03-07 21:15:39 +0100 |
commit | fb8c91a35c0a1c357aab96a6721a8b65c93368b0 (patch) | |
tree | 2071a8a79753305d413ce2c70c084902e9cd7044 /doc/ref | |
parent | 84a740d86a5afd235f1b47ac66c88db010b1d56b (diff) | |
download | guile-fb8c91a35c0a1c357aab96a6721a8b65c93368b0.tar.gz |
Add thread local fluids
* libguile/fluids.h (struct scm_dynamic_state): Add thread_local_values
table. Thread locals are flushed to a separate thread-local table.
The references are strong references since the table never escapes the
thread.
(scm_make_thread_local_fluid, scm_fluid_thread_local_p): New
functions.
* libguile/fluids.c (FLUID_F_THREAD_LOCAL):
(SCM_I_FLUID_THREAD_LOCAL_P): New macros.
(restore_dynamic_state): Add comment about precondition.
(save_dynamic_state): Flush thread locals.
(scm_i_fluid_print): Print thread locals nicely.
(new_fluid): Add flags arg.
(scm_make_fluid, scm_make_fluid_with_default, scm_make_unbound_fluid):
Adapt.
(scm_make_thread_local_fluid, scm_fluid_thread_local_p): New
functions.
(fluid_set_x): Special flushing logic for thread-locals.
(fluid_ref): Special cache miss logic for thread locals.
* libguile/stacks.c (scm_init_stacks):
* libguile/throw.c (scm_init_throw): %stacks and %exception-handler are
thread-locals.
* libguile/threads.c (guilify_self_2): Init thread locals table.
* test-suite/tests/fluids.test ("dynamic states"): Add test.
* doc/ref/api-control.texi (Fluids and Dynamic States): Add link to
Thread-Local Variables.
* doc/ref/api-scheduling.texi (Thread Local Variables): Update with real
thread-locals.
* NEWS: Update.
Diffstat (limited to 'doc/ref')
-rw-r--r-- | doc/ref/api-control.texi | 3 | ||||
-rw-r--r-- | doc/ref/api-scheduling.texi | 54 |
2 files changed, 38 insertions, 19 deletions
diff --git a/doc/ref/api-control.texi b/doc/ref/api-control.texi index 77d98b44e..b0c9e7202 100644 --- a/doc/ref/api-control.texi +++ b/doc/ref/api-control.texi @@ -1727,6 +1727,9 @@ used for testing whether an object is actually a fluid. The values stored in a fluid can be accessed with @code{fluid-ref} and @code{fluid-set!}. +@xref{Thread-Local Variables}, for further notes on fluids, threads, +parameters, and dynamic states. + @deffn {Scheme Procedure} make-fluid [dflt] @deffnx {C Function} scm_make_fluid () @deffnx {C Function} scm_make_fluid_with_default (dflt) diff --git a/doc/ref/api-scheduling.texi b/doc/ref/api-scheduling.texi index ff8473ae2..7b39a03d6 100644 --- a/doc/ref/api-scheduling.texi +++ b/doc/ref/api-scheduling.texi @@ -9,7 +9,7 @@ @menu * Threads:: Multiple threads of execution. -* Thread Local Variables:: Guile doesn't really have these. +* Thread Local Variables:: Some fluids are thread-local. * Asyncs:: Asynchronous interrupts. * Atomics:: Atomic references. * Mutexes and Condition Variables:: Synchronization primitives. @@ -169,9 +169,7 @@ information. @subsection Thread-Local Variables Sometimes you want to establish a variable binding that is only valid -for a given thread: a ``thread-local variable''. Guile doesn't really -have this facility, but what it does have can work well for most use -cases we know about. +for a given thread: a ``thread-local variable''. You would think that fluids or parameters would be Guile's answer for thread-local variables, since establishing a new fluid binding doesn't @@ -191,26 +189,44 @@ bindings comes from a desire to isolate a binding from its setting in unrelated threads, then fluids and parameters apply nicely. On the other hand, if your use case is to prevent concurrent access to a -value from multiple threads, then using fluids or parameters is not -appropriate. In this case, our current suggestion is to use weak hash -tables or object properties whose keys are thread objects. For example: +value from multiple threads, then using vanilla fluids or parameters is +not appropriate. For this purpose, Guile has @dfn{thread-local fluids}. +A fluid created with @code{make-thread-local-fluid} won't be captured by +@code{current-dynamic-state} and won't be propagated to new threads. -@example -(define (get-my-sensitive-data-structure) - ...) +@deffn {Scheme Procedure} make-thread-local-fluid [dflt] +@deffnx {C Function} scm_make_thread_local_fluid (dflt) +Return a newly created fluid, whose initial value is @var{dflt}, or +@code{#f} if @var{dflt} is not given. Unlike fluids made with +@code{make-fluid}, thread local fluids are not captured by +@code{make-dynamic-state}. Similarly, a newly spawned child thread does +not inherit thread-local fluid values from the parent thread. +@end deffn + +@deffn {Scheme Procedure} fluid-thread-local? fluid +@deffnx {C Function} scm_fluid_thread_local_p (fluid) +Return @code{#t} if the fluid @var{fluid} is is thread-local, or +@code{#f} otherwise. +@end deffn + +For example: -(define %thread-local (make-weak-key-hash-table)) +@example +(define %thread-local (make-thread-local-fluid)) -(define (current-thread-local) - (or (hashq-ref %thread-local (current-thread)) - (let ((val (get-my-sensitive-data-structure))) - (hashq-set! %thread-local (current-thread) val) - val))) +(with-fluids ((%thread-local (compute-data))) + ... (fluid-ref %thread-local) ...) @end example -It's not a terribly nice facility and perhaps we should have a better -answer, like Racket's ``non-preserved thread cells''. Your input is -very welcome; we look forward to hearing from your experience. +You can also make a thread-local parameter out of a thread-local fluid +using the normal @code{fluid->parameter}: + +@example +(define param (fluid->parameter (make-thread-local-fluid))) + +(parameterize ((param (compute-data))) + ... (param) ...) +@end example @node Asyncs |