libcamera  v0.2.0+110-fb74bb7d
Supporting cameras in Linux since 2019
Thread Support

libcamera supports multi-threaded applications through a threading model that sets precise rules to guarantee thread-safe usage of the API. Additionally, libcamera makes internal use of threads, and offers APIs that simplify interactions with application threads. Careful compliance with the threading model will ensure avoidance of race conditions.

Every thread created by libcamera is associated with an instance of the Thread class. Those threads run an internal event loop by default to dispatch events to objects. Additionally, the main thread of the application (defined as the thread that calls CameraManager::start()) is also associated with a Thread instance, but has no event loop accessible to libcamera. Other application threads are not visible to libcamera.

Threads and Objects

Instances of the Object class and all its derived classes are thread-aware and are bound to the thread they are created in. They are said to live in a thread, and they interact with the event loop of their thread for the purpose of message passing and signal delivery. Messages posted to the object with Object::postMessage() will be delivered from the event loop of the thread that the object lives in. Signals delivered to the object, unless explicitly connected with ConnectionTypeDirect, will also be delivered from the object thread's event loop.

All Object instances created internally by libcamera are bound to internal threads. As objects interact with thread event loops for proper operation, creating an Object instance in a thread that has no internal event loop (such as the main application thread, or libcamera threads that have a custom main loop), prevents some features of the Object class from being used. See Thread::exec() for more details.

Threads and Signals

When sent to a receiver that does not inherit from the Object class, signals are delivered synchronously in the thread of the sender. When the receiver inherits from the Object class, delivery is by default asynchronous if the sender and receiver live in different threads. In that case, the signal is posted to the receiver's message queue and will be delivered from the receiver's event loop, running in the receiver's thread. This mechanism can be overridden by selecting a different connection type when calling Signal::connect().

Reentrancy and Thread-Safety

Through the documentation, several terms are used to define how classes and their member functions can be used from multiple threads.

Neither reentrancy nor thread-safety, in this context, mean that a function may be called simultaneously from the same thread, for instance from a callback invoked by the function. This may deadlock and isn't allowed unless separately documented.

A class is defined as reentrant, thread-safe or thread-bound if all its member functions are reentrant, thread-safe or thread-bound respectively. Some member functions may additionally be documented as having additional thread-related attributes.

Most classes are reentrant but not thread-safe, as making them fully thread-safe would incur locking costs considered prohibitive for the expected use cases.