custom.texi 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. @node Custom thread synchronization
  2. @section Custom thread synchronization
  3. @cindex suspending threads
  4. @cindex resuming suspended threads
  5. @stindex threads-internal
  6. Along with several useful thread synchronization abstraction facilities
  7. built-in to Scheme48, there is also a simple and lower-level mechanism
  8. for suspending & resuming threads. The following bindings are exported
  9. from the @code{threads-internal} structure.
  10. @cindex thread cells
  11. @cindex thread queues
  12. Threads have a field for a @embedref{Cells, cell} that is used when the
  13. thread is suspended. When it is ready to run, it is simply @code{#f}.
  14. Suspending a thread involves setting its cell to a cell accessible
  15. outside, so the thread can later be awoken. When the thread is awoken,
  16. its cell field and the contents of the cell are both set to @code{#f}.
  17. Often, objects involved in the synchronization of threads will have a
  18. @embedref{Queues, queue} of thread cells. There are two specialized
  19. operations on thread cell queues that simplify filtering out cells of
  20. threads that have already been awoken.
  21. @deffn procedure maybe-commit-and-block cell @returns{} boolean
  22. @deffnx procedure maybe-commit-and-block-on-queue @returns{} boolean
  23. These attempt to commit the current proposal. If the commit fails,
  24. they immediately return @code{#f}. Otherwise, they suspend the current
  25. thread. @code{Maybe-commit-and-block} first sets the current thread's
  26. cell to @var{cell}, which should contain the current thread.
  27. @code{Maybe-commit-and-block-on-queue} adds a cell containing the
  28. current thread to @var{queue} first. When the current thread is
  29. finally resumed, these return @code{#t}.
  30. @end deffn
  31. @deffn procedure maybe-commit-and-make-ready thread-or-queue @returns{} boolean
  32. Attempts to commit the current proposal. If the commit fails, this
  33. returns @code{#f}. Otherwise, @code{maybe-commit-and-make-ready}
  34. awakens the specified thread[s] by clearing the thread/each thread's
  35. cell and sending a message to the relevant scheduler[s] and returns
  36. @code{#t}. If @var{thread-or-queue} is a thread, it simply awakens
  37. that; if it is a queue, it empties the queue and awakens each thread in
  38. it.
  39. @end deffn
  40. @deffn procedure maybe-dequeue-thread! thread-cell-queue @returns{} thread or boolean
  41. @deffnx procedure thread-queue-empty? thread-cell-queue @returns{} boolean
  42. @code{Maybe-dequeue-thread!} returns the next thread cell's contents in
  43. the queue of thread cells @var{thread-cell-queue}. It removes cells
  44. that have been emptied, @ie{} whose threads have already been awoken.
  45. @code{Thread-queue-empty?} returns @code{#t} if there are no cells in
  46. @var{thread-cell-queue} that contain threads, @ie{} threads that are
  47. still suspended. It too removes cells that have been emptied.
  48. @end deffn
  49. For example, the definition of @embedref{Higher-level synchronization,
  50. placeholders} is presented here. Placeholders contain two fields: the
  51. cached value (set when the placeholder is set) & a queue of threads
  52. waiting (set to @code{#f} when the placeholder is assigned).
  53. @lisp
  54. (define-synchronized-record-type placeholder :placeholder
  55. (really-make-placeholder queue)
  56. (value queue) ; synchronized fields
  57. placeholder?
  58. (queue placeholder-queue set-placeholder-queue!)
  59. (value placeholder-real-value set-placeholder-value!))
  60. (define (make-placeholder)
  61. (really-make-placeholder (make-queue)))
  62. (define (placeholder-value placeholder)
  63. ;; Set up a new proposal for the transaction.
  64. (with-new-proposal (lose)
  65. (cond ((placeholder-queue placeholder)
  66. ;; There's a queue of waiters. Attempt to commit the
  67. ;; proposal and block. We'll be added to the queue if the
  68. ;; commit succeeds; if it fails, retry.
  69. => (lambda (queue)
  70. (or (maybe-commit-and-block-on-queue queue)
  71. (lose))))))
  72. ;; Once our thread has been awoken, the placeholder will be set.
  73. (placeholder-real-value placeholder))
  74. (define (placeholder-set! placeholder value)
  75. ;; Set up a new proposal for the transaction.
  76. (with-new-proposal (lose)
  77. (cond ((placeholder-queue placeholder)
  78. => (lambda (queue)
  79. ;; Clear the queue, set the value field.
  80. (set-placeholder-queue! placeholder #f)
  81. (set-placeholder-value! placeholder value)
  82. ;; Attempt to commit our changes and awaken all of the
  83. ;; waiting threads. If the commit fails, retry.
  84. (if (not (maybe-commit-and-make-ready queue))
  85. (lose))))
  86. (else
  87. ;; Someone assigned it first. Since placeholders are
  88. ;; single-assignment cells, this is an error.
  89. (error "placeholder is already assigned"
  90. placeholder
  91. (placeholder-real-value placeholder))))))@end lisp