123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- @node Custom thread synchronization
- @section Custom thread synchronization
- @cindex suspending threads
- @cindex resuming suspended threads
- @stindex threads-internal
- Along with several useful thread synchronization abstraction facilities
- built-in to Scheme48, there is also a simple and lower-level mechanism
- for suspending & resuming threads. The following bindings are exported
- from the @code{threads-internal} structure.
- @cindex thread cells
- @cindex thread queues
- Threads have a field for a @embedref{Cells, cell} that is used when the
- thread is suspended. When it is ready to run, it is simply @code{#f}.
- Suspending a thread involves setting its cell to a cell accessible
- outside, so the thread can later be awoken. When the thread is awoken,
- its cell field and the contents of the cell are both set to @code{#f}.
- Often, objects involved in the synchronization of threads will have a
- @embedref{Queues, queue} of thread cells. There are two specialized
- operations on thread cell queues that simplify filtering out cells of
- threads that have already been awoken.
- @deffn procedure maybe-commit-and-block cell @returns{} boolean
- @deffnx procedure maybe-commit-and-block-on-queue @returns{} boolean
- These attempt to commit the current proposal. If the commit fails,
- they immediately return @code{#f}. Otherwise, they suspend the current
- thread. @code{Maybe-commit-and-block} first sets the current thread's
- cell to @var{cell}, which should contain the current thread.
- @code{Maybe-commit-and-block-on-queue} adds a cell containing the
- current thread to @var{queue} first. When the current thread is
- finally resumed, these return @code{#t}.
- @end deffn
- @deffn procedure maybe-commit-and-make-ready thread-or-queue @returns{} boolean
- Attempts to commit the current proposal. If the commit fails, this
- returns @code{#f}. Otherwise, @code{maybe-commit-and-make-ready}
- awakens the specified thread[s] by clearing the thread/each thread's
- cell and sending a message to the relevant scheduler[s] and returns
- @code{#t}. If @var{thread-or-queue} is a thread, it simply awakens
- that; if it is a queue, it empties the queue and awakens each thread in
- it.
- @end deffn
- @deffn procedure maybe-dequeue-thread! thread-cell-queue @returns{} thread or boolean
- @deffnx procedure thread-queue-empty? thread-cell-queue @returns{} boolean
- @code{Maybe-dequeue-thread!} returns the next thread cell's contents in
- the queue of thread cells @var{thread-cell-queue}. It removes cells
- that have been emptied, @ie{} whose threads have already been awoken.
- @code{Thread-queue-empty?} returns @code{#t} if there are no cells in
- @var{thread-cell-queue} that contain threads, @ie{} threads that are
- still suspended. It too removes cells that have been emptied.
- @end deffn
- For example, the definition of @embedref{Higher-level synchronization,
- placeholders} is presented here. Placeholders contain two fields: the
- cached value (set when the placeholder is set) & a queue of threads
- waiting (set to @code{#f} when the placeholder is assigned).
- @lisp
- (define-synchronized-record-type placeholder :placeholder
- (really-make-placeholder queue)
- (value queue) ; synchronized fields
- placeholder?
- (queue placeholder-queue set-placeholder-queue!)
- (value placeholder-real-value set-placeholder-value!))
- (define (make-placeholder)
- (really-make-placeholder (make-queue)))
- (define (placeholder-value placeholder)
- ;; Set up a new proposal for the transaction.
- (with-new-proposal (lose)
- (cond ((placeholder-queue placeholder)
- ;; There's a queue of waiters. Attempt to commit the
- ;; proposal and block. We'll be added to the queue if the
- ;; commit succeeds; if it fails, retry.
- => (lambda (queue)
- (or (maybe-commit-and-block-on-queue queue)
- (lose))))))
- ;; Once our thread has been awoken, the placeholder will be set.
- (placeholder-real-value placeholder))
- (define (placeholder-set! placeholder value)
- ;; Set up a new proposal for the transaction.
- (with-new-proposal (lose)
- (cond ((placeholder-queue placeholder)
- => (lambda (queue)
- ;; Clear the queue, set the value field.
- (set-placeholder-queue! placeholder #f)
- (set-placeholder-value! placeholder value)
- ;; Attempt to commit our changes and awaken all of the
- ;; waiting threads. If the commit fails, retry.
- (if (not (maybe-commit-and-make-ready queue))
- (lose))))
- (else
- ;; Someone assigned it first. Since placeholders are
- ;; single-assignment cells, this is an error.
- (error "placeholder is already assigned"
- placeholder
- (placeholder-real-value placeholder))))))@end lisp
|