...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Boost.Fiber enables synchronization of fibers
running on different threads per default. This is accomplished by spinlocks
(using atomics). (BOOST_FIBERS_SPINLOCK_STD_MUTEX defined at the compiler’s
command line enables std::mutex
instead of spinlocks).
With BOOST_FIBERS_NO_ATOMICS
defined at the compiler’s command line, synchronization between fibers (in
different threads) is disabled. This is acceptable if the application is
single threaded and/or fibers are not synchronized between threads.
Spinlocks are implemented as TTAS locks, i.e. the spinlock tests the lock before calling an atomic exchange. This strategy helps to reduce the cache line invalidations triggered by acquiring/releasing the lock.
A lock is considered under high contention, if a thread repeatedly fails to acquire the lock because some other thread was faster. Waiting for a short time lets other threads finish before trying to enter the critical section again. While busy waiting on the lock, relaxing the CPU (via pause/yield memnonic) gives the CPU a hint that the code is in a spin-wait loop.
It is obvious that this strategy is useless on single core systems because
the lock can only released if the thread gives up its time slice in order
to let other threads run. The macro BOOST_FIBERS_SPIN_SINGLE_CORE disables
active spinning, in other words, the operating system is notified (via std::this_thread_yield()
) that the thread gives up its time slice
and the operating system switches to another thread.
The macro BOOST_FIBERS_SPIN_MAX_TESTS determines how many times the CPU iterates in the spin-wait loop before yielding the thread or blocking in futex-wait. The spinlock tracks how many times the thread failed to acquire the lock. The higher the contention, the longer the thread should back-off. A “Binary Exponential Backoff” algorithm together with a randomized contention window is utilized for this purpose. BOOST_FIBERS_SPIN_MAX_COLLISIONS determines the upper limit of collisions between threads after the thread waits on a futex.
Table 1.4. macros for tweaking
Macro |
Effect on Boost.Fiber |
---|---|
BOOST_FIBERS_NO_ATOMICS |
no multithreading support, all atomics removed, no synchronization between fibers running in different threads |
BOOST_FIBERS_SPINLOCK_STD_MUTEX |
|
BOOST_FIBERS_SPINLOCK_TTAS |
spinlock with test-test-and-swap on shared variable |
BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE |
spinlock with test-test-and-swap on shared variable, adaptive retries while busy waiting |
BOOST_FIBERS_SPINLOCK_TTAS_FUTEX |
spinlock with test-test-and-swap on shared variable, suspend on futex after certain number of retries |
BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_FUTEX |
spinlock with test-test-and-swap on shared variable, while busy waiting adaptive retries, suspend on futex certain amount of retries |
BOOST_FIBERS_SPIN_SINGLE_CORE |
on single core machines with multiple threads, yield thread ( |
BOOST_FIBERS_SPIN_MAX_TESTS |
max number of retries while busy spinning |
BOOST_FIBERS_SPIN_MAX_COLLISIONS |
max number of collisions between contending threads |