[Openmcl-devel] question on process-allow-schedule and process-wait
Gary Byers
gb at clozure.com
Thu Mar 25 17:28:11 PST 2004
--On Thursday, March 25, 2004 1:15 PM -0500 Gary King <gwking at cs.umass.edu>
wrote:
> The documentation for both process-allow-schedule and process-wait state
> that "There's almost always a better alternative (involving waiting for
> some specific event to occur.)" I think I understand what this means in
> theory but I'm not sure how to use it in practice. Is there a simple
> example somewhere?
>
> thanks,
> --
> Gary Warren King, Lab Manager
> EKSL East, University of Massachusetts * 413 577 0176
>
Perhaps the suggestion shouldn't be to wait for "some specific event", but
to wait for "some event involving an object that the OS can use for thread
synchronization and scheduling, such as a lock, file descriptor, or
semaphore."
PROCESS-WAIT winds up having to make scheduling decisions: if it checks the
predicate too frequently,
it takes scheduling resources away from other threads/programs/the OS (and
perhaps interferes with whatever would cause the predicate to become true);
if it doesn't poll often enough, the latency between the time the predicate
becomes true and the time that it's tested may be unacceptably high.
PROCESS-WAIT was integrated with the lisp scheduler in earlier versions of
OpenMCL (and it or something like it would likely be integrated with the
scheduler of other implementations that use cooperatively scheduled
threads.) In those implementations (certainly in earlier OpenMCL
versions), you generally had to avoid the use of blocking primitives (since
their use typically prevented the lisp scheduler from running). In 0.14,
it's not only possible to use blocking primitives but it's preferable to do
so.
As an example (off the top of my head: beware of typos and other
brain-damage): suppose that we have two threads - a "producer" and
"consumer" of something or other - that need to coordinate their
activities: the consumer can only consume when the producer has produced
something, and the producer should only produce when the consumer's done
consuming. We might have done this via PROCESS-WAIT in a cooperatively
scheduled lisp via something like:
(defparameter *ready* nil "producer has produced data when true")
(defparameter *done* nil "consumer has consumed data when true")
(process-run-function "producer"
#'(lambda ()
(loop
(produce)
(without-interrupts (setq *done* nil *ready* t))
(process-wait "waiting for *done*" #'(lambda () *done*)))))
(process-run-function "consumer"
#'(lambda ()
(loop
(process-wait "waiting for *ready*" #'(lambda () *ready*))
(consume)
(without-interrupts (setq *ready* nil *done* t))
We -might- find that that's more-or-less adequate in 0.14 (perhaps we'd
need to be a little more careful about updating the special variables
atomically.) Depending on how complicated PRODUCE and CONSUME are, on what
other threads are running, and on other factors, it might be better to use
semaphores and get rid of PROCESS-WAIT:
(defparameter *ready* (make-semaphore))
(defparameter *done* (make-semaphore))
(process-run-function "producer"
#'(lambda ()
(loop
(produce)
(signal-semaphore *ready*)
(wait-on-semaphore *done*))))
(process-run-function "consume"
#'(lambda ()
(loop
(wait-on-semaphore *ready*)
(consume)
(signal-semaphore *done*)))
In the latter version, both threads will either be:
a) producing or consuming with little or no resource contention from the
other thread
b) signaling a semaphore, which is a constant-time operation
c) put to sleep by the OS and consuming no scheduling resources at all.
Again, how much those conditions matter depends on what PRODUCE and CONSUME
are doing and on what else is going on; this may or may not be a compelling
example.
More information about the Openmcl-devel
mailing list