|Paste number 1644:||BORDEAUX-MP|
|When:||10 years, 11 months ago|
|Share:||Tweet this! | http://paste.lisp.org/+19O|
BORDEAUX-MP is a proposed standard for a minimal MP/Threading interface. This is similar to the CLIM-SYS threading and lock support, but for the following broad differences: 1) Some behaviours are defined in additional detail: attention has been given to special variable interaction, whether and when cleanup forms are run. Some behaviours are defined in less detail: an implementation that does not support multiple processes is not required to use a new list (nil) for a lock, for example. 2) Many functions which would be difficult, dangerous or inefficient to provide on some implementations have been removed. Chiefly these are functions such as process-wait which expect for efficiency that the process scheduler is written in Lisp and 'hookable', which can't sensibly be done if the scheduler is external to the Lisp image, or the system has more than one CPU. 3) Unbalanced ACQUIRE-LOCK and RELEASE-LOCK functions have been added 4) Posix-style condition variables have been added, as it's not otherwise possible to implement them correctly using the other operations that are specified. Terminology note: to remain consistent with the vocabulary of existing Lisp environments, the term <b>process</b> as used here describes a context of execution which shares its Lisp environment with other such processes. This is <i>not</i> the concept of a process in some operating systems (e.g. Unix, NT) in which each OS process has an independent address space and cannot access or alter objects in other processes. What we call a "process" here is typically known as a "thread" in those circles. Processes (in the Lisp sense) may be implemented using whatever applicable techniques are provided by the operating system: user-space scheduling, kernel-based LWPs or anything else that does the job. Some parts of this specification can also be implemented in a Lisp that does not support multiple processes. Process creation and some process inspection operations will not work, but the locking functions are still present (though they may do nothing) so that thread-safe code can be compiled on both threaded and single-thread implementations without need of conditionals. To avoid conflict with existing MP/threading interfaces in implementations, these symbols live in the BORDEAUX-MP package. Implementations and/or users may also make them visible or exported in other more traditionally named packages. * Process Creation make-process function &key name [Function] Creates a process named NAME. The new process will evaluate the function FUNCTION. On systems that do not support multi-processing, make-process will signal an error. Initial values of special variables in the new process are implementation-defined. For example, they may be the same as in the process that called make-process, or set from the global values of the variables, or from a configurable list. The new thread may bind special variables: the new bindings are local to that thread. If it assigns to special variables without rebinding them, the effect is implementation-defined. current-process [Function] Returns the process object for the calling process. This is the same kind of object as would be returned by MAKE-PROCESS. processp object [Predicate] Returns true if object is a process, otherwise NIL. process-name process [Function] Returns the name of the process, as supplied to MAKE-PROCESS * Atomic operations atomic-incf reference [Function] atomic-decf reference [Function] Increments (or decrements) the fixnum value referred to by reference as a single, atomic operation. If the operation would take the value out of fixnum range, behaviour is undefined. * Resource contention: locks and recursive locks make-lock &optional name [Function] Creates a lock whose name is name. If the system does not support multiple processes this will still work, but the lock is just not useful for very much. acquire-lock lock wait-p [Function] Acquire the lock LOCK for the calling process. If the lock is not available, and if WAIT-P is supplied and non-NIL, wait until it is. This specification does not define what happens if a process attempts to acquire a lock that it already holds. For applications that require locks to be safe when acquired recursively, see instead MAKE-RECURSIVE-LOCK and friends. release-lock lock [Function] Release LOCK. It is an error to call this unless the lock has previously been acquired (and not released) by the same process. If other processes are waiting for the lock, the ACQUIRE-LOCK call in one of them will now be able to continue. with-lock-held (place) &body body [Macro] Evaluates BODY with the lock named by PLACE, which is a reference to a lock created by MAKE-LOCK. WITH-LOCK-HELD is implemented as if by use of ACQUIRE-LOCK, RELEASE-LOCK and UNWIND-PROTECT. If the process is interrupted and unable to acquire the lock, BODY will not be evaluated. make-recursive-lock &optional name [Function] Creates a recursive lock whose name is NAME. A recursive lock differs from an ordinary lock in that a process that already holds the recursive lock can acquire it again without blocking. The process must then release the lock twice before it becomes available for another process. acquire-recursive-lock lock [Function] As for ACQUIRE-LOCK, but for recursive locks. release-recursive-lock lock [Function] Release the recursive LOCK. The lock will only become free after as many Release operations as there have been Acquire operations. See RELEASE-LOCK for other information. with-recursive-lock-held (place &key timeout) &body body [Macro] Evaluates BODY with the recursive lock named by PLACE, which is a reference to a recursive lock created by MAKE-RECURSIVE-LOCK. See WITH-LOCK-HELD etc etc * Resource contention: condition variables Condition variables are for use when you have a shared resource with some kind of state, and the decision as to which process may run next is dependent on that state. For example: a buffer with readers and a writer, where the readers can only run when there is data in the buffer, and the writer can only refill the buffer when it is empty. There are three parts to any system involving a condition variable - the condition itself. In this example it would be "buffer is (not) empty" and "buffer is not empty". This is not apparent in the actual code. - a lock to protect the sections of code that evaluate the condition. - a condition-variable object; this is essentially a queue of processes waiting for the condition to change. make-condition-variable () [function] Returns a new condition-variable object for use with CONDITION-WAIT and CONDITION-NOTIFY. condition-wait (condition-variable lock) [function] Atomically release LOCK and enqueue ourselves waiting for CONDITION-VARIABLE. The process will resume when another thread has notified us using CONDITION-NOTIFY, or we are interrupted, or in other implementation-dependent circumstances: the caller must always test the condition on waking before continuing normal processing. However and for whatever reason the process is resumed, the system always reacquires LOCK before returning to the caller. It is an error to call this unless from the thread that holds LOCK. In an implementation that does not support multiple processes, this function signals an error. condition-notify (condition-variable) [function] Notify one or more of the processes waiting for CONDITION-VARIABLE. The caller needs to acquire the lock associated with the condition variable before calling this. In an implementation that does not support multiple processes, this function has no effect. process-yield [Function] Allows other processes to run. It may be necessary or desirable to call this periodically in some implementations; others may schedule processes automatically. On systems that do not support multi-processing, this does nothing. * Introspection/debugging The following functions may be provided for debugging purposes, but are not advised to be called from normal user code. all-processes [Function] Returns a sequence of all of the processes. process-interrupt process function [Function] Interrupt PROCESS and cause it to evaluate FUNCTION before continuing with the interrupted path of execution. This may not be a good idea if PROCESS is holding locks or doing anything important. On systems that do not support multiple processes, this function signals an error. destroy-process process [Function] Terminates the process PROCESS, which is an object as returned by MAKE-PROCESS. This should be used with caution: it is implementation-defined whether the process runs cleanup forms or releases its locks first. Destroying the calling process is an error.
This paste has no annotations.