SDL3pp
A slim C++ wrapper for SDL3
|
Atomic operations. More...
Classes | |
class | SDL::AtomicInt |
A type representing an atomic integer value. More... | |
class | SDL::AtomicU32 |
A type representing an atomic unsigned 32-bit value. More... | |
class | SDL::AtomicPointer< T > |
Type representing an atomic pointer. More... | |
Macros | |
#define | SDL_CompilerBarrier() DoCompilerSpecificReadWriteBarrier() |
Mark a compiler barrier. | |
#define | SDL_MemoryBarrierRelease() SDL_MemoryBarrierReleaseFunction() |
Insert a memory release barrier (macro version). | |
#define | SDL_MemoryBarrierAcquire() SDL_MemoryBarrierAcquireFunction() |
Insert a memory acquire barrier (macro version). | |
#define | SDL_CPUPauseInstruction() DoACPUPauseInACompilerAndArchitectureSpecificWay |
A macro to insert a CPU-specific "pause" instruction into the program. | |
Functions | |
void | SDL::MemoryBarrierRelease () |
Insert a memory release barrier (function version). | |
void | SDL::MemoryBarrierAcquire () |
Insert a memory acquire barrier (function version). | |
IMPORTANT: If you are not an expert in concurrent lockless programming, you should not be using any functions in this file. You should be protecting your data structures with full mutexes instead.
Seriously, here be dragons!
You can find out a little more about lockless programming and the subtle issues that can arise here: https://learn.microsoft.com/en-us/windows/win32/dxtecharts/lockless-programming
There's also lots of good information here:
These operations may or may not actually be implemented using processor specific atomic operations. When possible they are implemented as true processor specific atomic operations. When that is not possible the are implemented using locks that do use the available atomic operations.
All of the atomic operations that modify memory are full memory barriers.
#define SDL_CompilerBarrier | ( | ) | DoCompilerSpecificReadWriteBarrier() |
A compiler barrier prevents the compiler from reordering reads and writes to globally visible variables across the call.
This macro only prevents the compiler from reordering reads and writes, it does not prevent the CPU from reordering reads and writes. However, all of the atomic operations that modify memory are full memory barriers.
#define SDL_CPUPauseInstruction | ( | ) | DoACPUPauseInACompilerAndArchitectureSpecificWay |
This can be useful in busy-wait loops, as it serves as a hint to the CPU as to the program's intent; some CPUs can use this to do more efficient processing. On some platforms, this doesn't do anything, so using this macro might just be a harmless no-op.
Note that if you are busy-waiting, there are often more-efficient approaches with other synchronization primitives: mutexes, semaphores, condition variables, etc.
#define SDL_MemoryBarrierAcquire | ( | ) | SDL_MemoryBarrierAcquireFunction() |
Please see SDL_MemoryBarrierRelease for the details on what memory barriers are and when to use them.
This is the macro version of this functionality; if possible, SDL will use compiler intrinsics or inline assembly, but some platforms might need to call the function version of this, MemoryBarrierAcquire, to do the heavy lifting. Apps that can use the macro should favor it over the function.
#define SDL_MemoryBarrierRelease | ( | ) | SDL_MemoryBarrierReleaseFunction() |
Memory barriers are designed to prevent reads and writes from being reordered by the compiler and being seen out of order on multi-core CPUs.
A typical pattern would be for thread A to write some data and a flag, and for thread B to read the flag and get the data. In this case you would insert a release barrier between writing the data and the flag, guaranteeing that the data write completes no later than the flag is written, and you would insert an acquire barrier between reading the flag and reading the data, to ensure that all the reads associated with the flag have completed.
In this pattern you should always see a release barrier paired with an acquire barrier and you should gate the data reads/writes with a single flag variable.
For more information on these semantics, take a look at the blog post: http://preshing.com/20120913/acquire-and-release-semantics
This is the macro version of this functionality; if possible, SDL will use compiler intrinsics or inline assembly, but some platforms might need to call the function version of this, MemoryBarrierRelease to do the heavy lifting. Apps that can use the macro should favor it over the function.
|
inline |
Please refer to SDL_MemoryBarrierRelease for details. This is a function version, which might be useful if you need to use this functionality from a scripting language, etc. Also, some of the macro versions call this function behind the scenes, where more heavy lifting can happen inside of SDL. Generally, though, an app written in C/C++/etc should use the macro version, as it will be more efficient.
|
inline |
Please refer to SDL_MemoryBarrierRelease for details. This is a function version, which might be useful if you need to use this functionality from a scripting language, etc. Also, some of the macro versions call this function behind the scenes, where more heavy lifting can happen inside of SDL. Generally, though, an app written in C/C++/etc should use the macro version, as it will be more efficient.