GNU Emacs
ELisp
Threads
ELisp 30.2 elisp

Threads

Emacs Lisp provides a limited form of concurrency, called threads. All the threads in a given instance of Emacs share the same memory. Concurrency in Emacs Lisp is "mostly cooperative", meaning that Emacs will only switch execution between threads at well-defined times. However, the Emacs thread support has been designed in a way to later allow more fine-grained concurrency, and correct programs should not rely on cooperative threading. Currently, thread switching will occur upon explicit request via thread-yield, when waiting for keyboard input or for process output from asynchronous processes (e.g., during accept-process-output), or during blocking operations relating to threads, such as mutex locking or thread-join. Emacs Lisp provides primitives to create and control threads, and also to create and control mutexes and condition variables, useful for thread synchronization. While global variables are shared among all Emacs Lisp threads, local variables are not—a dynamic let binding is local. Each thread also has its own current buffer (Current Buffer) and its own match data (Match Data). Note that let bindings are treated specially by the Emacs Lisp implementation. There is no way to duplicate this unwinding and rewinding behavior other than by using let. For example, a manual implementation of let written using unwind-protect cannot arrange for variable values to be thread-specific. In the case of lexical bindings (Variable Scoping), a closure is an object like any other in Emacs Lisp, and bindings in a closure are shared by any threads invoking the closure.

Basic Thread Functions

Threads can be created and waited for. A thread cannot be exited directly, but the current thread can be exited implicitly, and other threads can be signaled.

make-thread
Create a new thread of execution which invokes function. When function returns, the thread exits. The new thread is created with no local variable bindings in effect. The new thread's current buffer is inherited from the current thread. name can be supplied to give a name to the thread. The name is used for debugging and informational purposes only; it has no meaning to Emacs. If name is provided, it must be a string. This function returns the new thread.
threadp
This function returns t if object represents an Emacs thread, nil otherwise.
thread-join
Block until thread exits, or until the current thread is signaled. It returns the result of the thread function. If thread has already exited, this returns immediately.
thread-signal
Like signal (Signaling Errors), but the signal is delivered in the thread thread. If thread is the current thread, then this just calls signal immediately. Otherwise, thread will receive the signal as soon as it becomes current. If thread was blocked by a call to mutex-lock, condition-wait, or thread-join; thread-signal will unblock it. If thread is the main thread, the signal is not propagated there. Instead, it is shown as message in the main thread.
thread-yield
Yield execution to the next runnable thread.
thread-name
Return the name of thread, as specified to make-thread.
thread-live-p
Return t if thread is alive, or nil if it is not. A thread is alive as long as its function is still executing.
thread--blocker
Return the object that thread is waiting on. This function is primarily intended for debugging, and is given a "double hyphen" name to indicate that. If thread is blocked in thread-join, this returns the thread for which it is waiting. If thread is blocked in mutex-lock, this returns the mutex. If thread is blocked in condition-wait, this returns the condition variable. Otherwise, this returns nil.
current-thread
Return the current thread.
all-threads
Return a list of all the live thread objects. A new list is returned by each invocation.
main-thread
This variable keeps the main thread Emacs is running, or nil if Emacs is compiled without thread support.

When code run by a thread signals an error that is unhandled, the thread exits. Other threads can access the error form which caused the thread to exit using the following function.

thread-last-error
This function returns the last error form recorded when a thread exited due to an error. Each thread that exits abnormally overwrites the form stored by the previous thread's error with a new value, so only the last one can be accessed. If cleanup is non-nil, the stored form is reset to nil.

Mutexes

A mutex is an exclusive lock. At any moment, zero or one threads may own a mutex. If a thread attempts to acquire a mutex, and the mutex is already owned by some other thread, then the acquiring thread will block until the mutex becomes available. Emacs Lisp mutexes are of a type called recursive, which means that a thread can re-acquire a mutex it owns any number of times. A mutex keeps a count of how many times it has been acquired, and each acquisition of a mutex must be paired with a release. The last release by a thread of a mutex reverts it to the unowned state, potentially allowing another thread to acquire the mutex.

mutexp
This function returns t if object represents an Emacs mutex, nil otherwise.
make-mutex
Create a new mutex and return it. If name is specified, it is a name given to the mutex. It must be a string. The name is for debugging purposes only; it has no meaning to Emacs.
mutex-name
Return the name of mutex, as specified to make-mutex.
mutex-lock
This will block until this thread acquires mutex, or until this thread is signaled using thread-signal. If mutex is already owned by this thread, this simply returns.
mutex-unlock
Release mutex. If mutex is not owned by this thread, this will signal an error.
with-mutex
This macro is the simplest and safest way to evaluate forms while holding a mutex. It acquires mutex, invokes body, and then releases mutex. It returns the result of body.

Condition Variables

A condition variable is a way for a thread to block until some event occurs. A thread can wait on a condition variable, to be woken up when some other thread notifies the condition. A condition variable is associated with a mutex and, conceptually, with some condition. For proper operation, the mutex must be acquired, and then a waiting thread must loop, testing the condition and waiting on the condition variable. For example:

(with-mutex mutex
  (while (not global-variable)
    (condition-wait cond-var)))

The mutex ensures atomicity, and the loop is for robustness—there may be spurious notifications. Similarly, the mutex must be held before notifying the condition. The typical, and best, approach is to acquire the mutex, make the changes associated with this condition, and then notify it:

(with-mutex mutex
  (setq global-variable (some-computation))
  (condition-notify cond-var))
make-condition-variable
Make a new condition variable associated with mutex. If name is specified, it is a name given to the condition variable. It must be a string. The name is for debugging purposes only; it has no meaning to Emacs.
condition-variable-p
This function returns t if object represents a condition variable, nil otherwise.
condition-wait
Wait for another thread to notify cond, a condition variable. This function will block until the condition is notified, or until a signal is delivered to this thread using thread-signal. It is an error to call condition-wait without holding the condition's associated mutex. condition-wait releases the associated mutex while waiting. This allows other threads to acquire the mutex in order to notify the condition.
condition-notify
Notify cond. The mutex with cond must be held before calling this. Ordinarily a single waiting thread is woken by condition-notify; but if all is not nil, then all threads waiting on cond are notified. condition-notify releases the associated mutex. This allows other threads to acquire the mutex in order to wait on the condition.
condition-name
Return the name of cond, as passed to make-condition-variable.
condition-mutex
Return the mutex associated with cond. Note that the associated mutex cannot be changed.

The Thread List

The list-threads command lists all the currently alive threads. In the resulting buffer, each thread is identified either by the name passed to make-thread (Basic Thread Functions), or by its unique internal identifier if it was not created with a name. The status of each thread at the time of the creation or last update of the buffer is shown, in addition to the object the thread was blocked on at the time, if it was blocked.

thread-list-refresh-seconds
The *Threads* buffer will automatically update twice per second. You can make the refresh rate faster or slower by customizing this variable.

Here are the commands available in the thread list buffer:

b
Show a backtrace of the thread at point. This will show where in its code the thread had yielded or was blocked at the moment you pressed b. Be aware that the backtrace is a snapshot; the thread could have meanwhile resumed execution, and be in a different state, or could have exited. You may use g in the thread's backtrace buffer to get an updated backtrace, as backtrace buffers do not automatically update. Backtraces, for a description of backtraces and the other commands which work on them.
s
Signal the thread at point. After s, type q to send a quit signal or e to send an error signal. Threads may implement handling of signals, but the default behavior is to exit on any signal. Therefore you should only use this command if you understand how to restart the target thread, because your Emacs session may behave incorrectly if necessary threads are killed.
g
Update the list of threads and their statuses.
Manual
Emacs Lisp 30.2
Texinfo Node
Threads
Source Ref
emacs-30.2
Source
View upstream