Multi-processing implemented by stack groups or continuations has been a popular approach for Common Lisp implementations. This approach is not practical in the Scieneer Common Lisp because threads are managed by the operating system and run concurrently. However a compatibility package is provided to make it easier to port applications. The multi-processing package is intended to be largely compatible with the requirements of the CLIM specification.
Multi-processing code that depends on inhibiting scheduling using mp:without-scheduling should be rewritten to use locks for synchronization. Implementations build on stack groups run only one process at a time and switch the context to run another process which allows fast atomic operations by simply inhibiting scheduling. This can be implemented in the Scieneer Common Lisp by stopping all other threads running, but this is a costly procedure, degrades scalability, and is problematic because the exclusive execution environment is fragile. Thus it is recommended that such code be rewritten.
Many atomic operations such at mp:atomic-incf, mp:atomic-decf, mp:atomic-push and mp:atomic-pop are well supported in the Scieneer Common Lisp and compile to a fast atomic machine code, but this is only applicable when the operation updates a single value cell and only for the limited range of supported places. When applicable, it is recommended that this Scieneer Common Lisp feature be used rather than converting code to use locks which are slower. If the place being updated is not supported for fast inline atomic operation then it is recommended that the code be rewritten to use locks. Scieneer will consider requests to extended the supported places.
Complex scheduling predicates should be rewritten to use locks and condition variables. Multi-processing implementations that use their own scheduler are able to support complex scheduling algorithms that call lisp predicates to decide which process to schedule for execution. Since the Scieneer Common Lisp uses native threads that are scheduled by the operating system it is problematic to support such scheduling control. The functions mp:process-wait and mp:process-wait-with-timeout are implemented by polling their predicates. The function mp:process-wakeup may be called to cause the target process to immediately poll its wait predicate and this can improve performance.
The use of mp:process-interrupt should be avoided in production code. Interrupting a process and causing an abort is not safe in the Scieneer Common Lisp. For example, the interrupted process could still have a lock held that could cause a deadlock, and many other issues are possible. Similarly mp:destroy-process, and mp:disable-process, which both interrupt another process should not be used in production code. Code should be rewritten to poll for exit flags and abort synchronously if necessary.
The mp:with-timeout macro is not implemented in the Scieneer Common Lisp as it would need to invoke an asynchronous interrupt upon timeout which would not be safe. The ext:stream-timeout and ext:stream-expiration functions are provided to implement timeouts on blocking stream operations. For the timeout of computation, code should be rewritten to poll the time and exit cleanup upon a timeout.
|mp:make-process function &key name background-streams-p||[Function]|
Make a process which will run function when it starts up. The process may be given an optional name which defaults to "Anonymous". The new process has a fresh set of dynamic special bindings. See also: thread:thread-create.
|mp:destroy-process process &optional wait||[Function]|
Destroy a process. The process is sent an interrupt which throws to the end of the process allowing it to unwind gracefully.
Warning: The process is not guaranteed to exit cleanly. For restrictions, see thread:thread-interrupt. When necessary, it is recommended that threads poll for exit events, such as an exit flag, and arrange to exit gracefully themselves.
|mp:process-preset process function &rest args||[Function]|
Restart process, installing a new initial function that will call function with args and then calling mp:restart-process.
Restart process by firstly calling mp:destroy-process and calling its initial function.
Disable process from being runnable until enabled by a call to mp:enable-process.
Allow process to become runnable again after it has been disabled by a call to mp:enable-process.
Return the process state which is either "Run", "Killed", or a wait reason.
Return the accrued real time elapsed while the given process was started. The returned time is a double-float in seconds. This implementation can only return the time for the current process, otherwise an error is generated.
Return the accrued run time elapsed for the given process. The returned time is a double-float in seconds. This implementation can only return the time for the current process, otherwise an error is generated.
Return a list of all the live processes.
Returns the current process.
|mp:show-processes &optional verbose||[Function]|
Show the all the processes, their whostate, and state. The optional verbose argument is ignored.
|kernel:atomic-decf place &optional delta||[Macro]|
Atomically decrease place by delta.
|kernel:atomic-incf place &optional delta||[Macro]|
Atomically increment place by delta.
|kernel:atomic-pop place &environment env||[Macro]|
Thread safe pop from the list in the given place.
|kernel:atomic-push value place &environment env||[Macro]|
Thread safe push of value onto the list in the given place.
|thread:make-lock &optional name &key type auto-free interruptible||[Function]|
Make a pthread-mutex based lock, returning a lisp thread:lock object encapsulating the pthread-mutex structure. The lock type may be :normal, :recursive, or :error-check. When auto-free is t, the pthread-rwlock structure will be automatically freed when the lisp object is no longer accessible, and reallocated when lisp is restarted. When auto-free is :note, the lock is noted and reallocated upon restart, but is not automatically freed.
|thread:with-lock-held (lock &optional whostate &key :wait :timeout) &body body||[Macro]|
Execute the body with the lock held. If the lock is held by another thread then wait until the lock is released or an optional :timeout is reached. The results of the body are returned upon success. When :wait is nil and the lock is held by another thread then nil is returned immediately without processing the body.
|mp:process-wait-until-fd-usable fd direction &optional timeout||[Function]|
Wait until fd is usable for direction and return true. The direction should be either :input, :output or :io. The timeout, if supplied, is the number of seconds to wait before giving up and returing nil.
|mp:process-wait whostate predicate &key polling-interval||[Function]|
Causes the process to wait until predicate returns true. The predicate can not call mp:process-wait. Since the predicate may be evaluated may times it should be relative fast native compiled code. This implementation retests the predicate at the polling-interval which defaults to 0.01 seconds, or when signaled by mp:process-wakeup. The single true predicate value is returned.
Signal the target process to immediately wakeup from a mp:process-wait or mp:process-wait-with-timeout and reevaluate its wait predicate. The target process does poll its wait predicate periodically so it is not necessary to call mp:process-wakeup, however it can improve performance by avoiding the delay to the next polling event.
|mp:process-wait-with-timeout whostate timeout predicate &key polling-interval||[Function]|
Causes the current process to wait until predicate returns true, or the number of seconds specified by timeout has elapsed. The timeout may be a fixnum or a float in seconds. The single true predicate value is returned, or nil if the timeout was reached. This implementation retests the predicate at the polling-interval which defaults to 0.01 seconds, or when signaled by mp:process-wakeup. The use of this function is not recommended - use locks and condition variables for threads synchronization.
|mp:process-interrupt process function||[Function]|
Interrupt process and cause it to evaluate function. See also: thread:thread-interrupt.
|mp:without-scheduling &body body||[Macro]|
Execute the body in an exclusive execution context, see thread:with-exclusive-execution.