reference: improve description of thread-based concurrency

Related to #2834
This commit is contained in:
Matthew Flatt 2019-09-27 09:18:18 -06:00
parent a07e973316
commit 10b110adc1
3 changed files with 36 additions and 19 deletions

View File

@ -953,18 +953,42 @@ Racket supports multiple @deftech{threads} of evaluation. Threads run
concurrently, in the sense that one thread can preempt another without
its cooperation, but threads currently all run on the same processor
(i.e., the same underlying operating system process and thread). See also
@secref["futures"].
@secref["futures"] and @secref["places"].
Threads are created explicitly by functions such as @racket[thread].
In terms of the evaluation model, each step in evaluation
actually deals with multiple concurrent
expressions, up to one per thread, rather than a single expression. The expressions all
share the same objects and top-level variables, so that they can
communicate through shared state, and sequential consistency is
communicate through shared state, and @defterm{sequential consistency} @cite["Lamport79"] is
guaranteed (i.e., the result is consistent with some global sequence
imposed on all evaluation steps across threads). Most evaluation steps involve a
single step in a single expression, but certain synchronization
primitives require multiple threads to progress together in one step.
single step in a single thread, but certain synchronization
primitives require multiple threads to progress together in one step; for example,
an exchange of a value through a @tech{channel} progresses in two
threads simultaneously.
Unless otherwise noted, all constant-time procedures and operations
provided by Racket are thread-safe in the sense that they are
@defterm{atomic}: they happen as a single evaluation step.
For example, @racket[set!] assigns to a variable as an atomic action
with respect to all threads, so that no thread can see a
``half-assigned'' variable. Similarly, @racket[vector-set!] assigns to
a vector atomically. Note that the evaluation of a @racket[set!]
expression with its subexpression is not necessarily atomic, because
evaluating the subexpression involves a separate step of evaluation.
Only the assignment action itself (which takes after the subexpression
is evaluated to obtain a value) is atomic. Similarly, a procedure
application can involve multiple steps that are not atomic, even if
the procedure itself performs an atomic action.
The @racket[hash-set!] procedure is not atomic, but the table is
protected by a lock; see @secref["hashtables"] for more information.
Port operations are generally not atomic, but they are thread-safe in
the sense that a byte consumed by one thread from an input port will
not be returned also to another thread, and procedures like
@racket[port-commit-peeked] and @racket[write-bytes-avail] offer
specific concurrency guarantees.
In addition to the state that is shared among all threads, each thread
has its own private state that is accessed through @deftech{thread

View File

@ -168,7 +168,13 @@ The @racketmodname[racket] library combines
#:location "Principles and Practice of Parallel Programming"
#:date "1990")
(bib-entry #:key "L'Ecuyer02"
(bib-entry #:key "Lamport79"
#:title "How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs"
#:author "Leslie Lamport"
#:location "IEEE Transactions on Computers"
#:date "179")
(bib-entry #:key "L'Ecuyer02"
#:author "Pierre L'Ecuyer, Richard Simard, E. Jack Chen, and W. David Kelton"
#:title "An Object-Oriented Random-Number Package With Many Long Streams and Substreams"
#:location "Operations Research, 50(6)"

View File

@ -6,7 +6,7 @@
@guideintro["concurrency"]{threads}
See @secref["thread-model"] for basic information on the Racket
thread model. See also @secref["futures"].
thread model. See also @secref["futures"] and @secref["places"].
When a thread is created, it is placed into the management of the
@tech{current custodian} and added to the current @tech{thread
@ -31,19 +31,6 @@ A thread can be used as a @tech{synchronizable event} (see
@secref["sync"]). A thread is @tech{ready for synchronization} when
@racket[thread-wait] would not block; @resultItself{thread}.
All constant-time procedures and operations provided by Racket are
thread-safe because they are @defterm{atomic}. For example,
@racket[set!] assigns to a variable as an atomic action with respect
to all threads, so that no thread can see a ``half-assigned''
variable. Similarly, @racket[vector-set!] assigns to a vector
atomically. The @racket[hash-set!] procedure is not atomic, but
the table is protected by a lock; see @secref["hashtables"] for more
information. Port operations are generally not atomic, but they are
thread-safe in the sense that a byte consumed by one thread from an
input port will not be returned also to another thread, and procedures
like @racket[port-commit-peeked] and @racket[write-bytes-avail] offer
specific concurrency guarantees.
@;------------------------------------------------------------------------
@section{Creating Threads}