Multithreading Functionality
UNIGINE Multithreading Functionality provides cross-platform, low and high-level abstractions for building efficient multithreaded systems.
It includes thread management, mutual exclusion primitives (mutexes), scoped lock wrappers, and full set of atomic operations and classes.
Mutexes and Locks#
Mutexes (mutual exclusions) are the primary tool for preventing simultaneous access to shared resources. UNIGINE provides various mutex types optimized for spinlocks, native system APIs, and reentrant behavior.
In most cases, you will only need a limited set of high-level classes and aliases that provide efficient and safe synchronization out of the box:
- Mutex - default mutex type using spinlock.
- ScopedLock - scoped lock for Mutex.
- ReentrantMutex - reentrant mutex based on spinlock.
- ScopedReentrantLock - scoped lock for ReentrantMutex.
- RWMutex - default readers-writer mutex based on spinlock.
- ScopedReaderLock - scoped read lock for RWMutex.
- ScopedWriterLock - scoped write lock for RWMutex.
If you need more control, platform-specific integration, or lower-level performance tuning, the library also provides spin-based mutexes, wrappers for native system APIs, scoped lock templates, and advanced mutex types with lock-state tracking.
Atomics#
Atomic types are essential for building safe and performant multithreaded applications. They allow shared data to be accessed and modified concurrently without introducing race conditions.
This atomic system provides a general-purpose Atomic<Type> template that automatically selects the most suitable underlying implementation: lock-free or mutex-based, depending on the size and type of the provided Type. This selection is fully resolved at compile time.
The Atomic<Type> template chooses between several internal implementations using type traits and size evaluations. The decision logic is based on both type category (integer, pointer, etc.) and data size, with specific checks for 8-bit, 16-bit, 32-bit, and 64-bit sizes. Based on this, a suitable raw storage type is chosen:
-
AtomicInteger<Type>
Used for standard integer types up to 64 bits (like int, short, long long, etc.), except for bool. This type supports atomic arithmetic and bitwise operations and is always lock-free.
-
AtomicPointer<Type>
Specialized for pointer types. Supports atomic pointer arithmetic and CAS operations. Also lock-free and size-aware.
-
AtomicLockFree<Type>
For all other trivially copyable types up to 64 bits:
- AtomicLockFreeRaw<Type> is used if the size matches exactly with the raw type.
- AtomicLockFreeAlign<Type> is used when type casting with unions is required to match size.
-
AtomicWithMutex<Type>
Fallback for types larger than 64 bits or not trivially copyable. This version is not lock-free but supports any type.
To simplify usage the following aliases are provided:
// Boolean
using AtomicBool = Atomic<bool>;
// Signed integers
using AtomicInt8 = Atomic<char>;
using AtomicInt16 = Atomic<short>;
using AtomicInt32 = Atomic<int>;
using AtomicInt64 = Atomic<long long>;
// Unsigned integers
using AtomicUInt8 = Atomic<unsigned char>;
using AtomicUInt16 = Atomic<unsigned short>;
using AtomicUInt32 = Atomic<unsigned int>;
using AtomicUInt64 = Atomic<unsigned long long>;
// Floating point
using AtomicFloat = Atomic<float>;
using AtomicDouble = Atomic<double>;
The information on this page is valid for UNIGINE 2.20 SDK.