Memory barrier
Page Module:Message box/ambox.css has no content.
This article needs additional citations for verification. (January 2016) |
In computing, a memory barrier, also known as a membar, memory fence or fence instruction, is a type of barrier instruction that causes a central processing unit (CPU) or compiler to enforce an ordering constraint on memory operations issued before and after the barrier instruction. This typically means that operations issued prior to the barrier are guaranteed to be performed before operations issued after the barrier.
Memory barriers are necessary because most modern CPUs employ performance optimizations that can result in out-of-order execution. This reordering of memory operations (loads and stores) normally goes unnoticed within a single thread of execution, but can cause unpredictable behavior in concurrent programs and device drivers unless carefully controlled. The exact nature of an ordering constraint is hardware dependent and defined by the architecture's memory ordering model. Some architectures provide multiple barriers for enforcing different ordering constraints.
Memory barriers are typically used when implementing low-level machine code that operates on memory shared by multiple devices. Such code includes synchronization primitives and lock-free data structures on multiprocessor systems, and device drivers that communicate with computer hardware.
Example
When a program runs on a single-CPU machine, the hardware performs the necessary bookkeeping to ensure that the program executes as if all memory operations were performed in the order specified by the programmer (program order), so memory barriers are not necessary. However, when the memory is shared with multiple devices, such as other CPUs in a multiprocessor system, or memory-mapped peripherals, out-of-order access may affect program behavior. For example, a second CPU may see memory changes made by the first CPU in a sequence that differs from program order.
A program is run via a process which can be multi-threaded (i.e. a software thread such as pthreads as opposed to a hardware thread). Different processes do not share a memory space so this discussion does not apply to two programs, each one running in a different process (hence a different memory space). It applies to two or more (software) threads running in a single process (i.e. a single memory space where multiple software threads share a single memory space). Multiple software threads, within a single process, may run concurrently on a multi-core processor.
The following multi-threaded program, running on a multi-core processor gives an example of how such out-of-order execution can affect program behavior:
Initially, memory locations Page Template:Mono/styles.css has no content.x and Page Template:Mono/styles.css has no content.f both hold the value Page Template:Mono/styles.css has no content.0. The software thread running on processor #1 loops while the value of Page Template:Mono/styles.css has no content.f is zero, then it prints the value of Page Template:Mono/styles.css has no content.x. The software thread running on processor #2 stores the value Page Template:Mono/styles.css has no content.42 into Page Template:Mono/styles.css has no content.x and then stores the value Page Template:Mono/styles.css has no content.1 into Page Template:Mono/styles.css has no content.f. Pseudo-code for the two program fragments is shown below.
The steps of the program correspond to individual processor instructions.
Thread #1 Core #1:
while (f == 0) {
continue;
}
// Memory fence required here
printf("%d", x);
Thread #2 Core #2:
x = 42;
// Memory fence required here
f = 1;
One might expect the print statement to always print the number "42"; however, if thread #2's store operations are executed out-of-order, it is possible for Page Template:Mono/styles.css has no content.f to be updated before Page Template:Mono/styles.css has no content.x, and the print statement might therefore print "0". Similarly, thread #1's load operations may be executed out-of-order and it is possible for Page Template:Mono/styles.css has no content.x to be read before Page Template:Mono/styles.css has no content.f is checked, and again the print statement might therefore print an unexpected value. For most programs neither of these situations is acceptable. A memory barrier must be inserted before thread #2's assignment to Page Template:Mono/styles.css has no content.f to ensure that the new value of Page Template:Mono/styles.css has no content.x is visible to other processors at or prior to the change in the value of Page Template:Mono/styles.css has no content.f. Another important point is a memory barrier must also be inserted before thread #1's access to Page Template:Mono/styles.css has no content.x to ensure the value of Page Template:Mono/styles.css has no content.x is not read prior to seeing the change in the value of Page Template:Mono/styles.css has no content.f.
Another example is when a driver performs the following sequence:
// prepare data for a hardware module
// Memory fence required here
// trigger the hardware module to process the data
If the processor's store operations are executed out-of-order, the hardware module may be triggered before data is ready in memory.
For another illustrative example (a non-trivial one that arises in actual practice), see double-checked locking.
In the case of the PowerPC processor, the eieio ("Enforce In-order Execution of I/O") instruction ensures, as memory fence, that any load or store operations previously initiated by the processor are fully completed with respect to the main memory before any subsequent load or store operations initiated by the processor access the main memory.[1][2]
In the case of the ARM architecture family, the Page Template:Mono/styles.css has no content.DMB,[3] Page Template:Mono/styles.css has no content.DSB[4] and Page Template:Mono/styles.css has no content.ISB[5] instructions are used.[6]
In the case of the RISC-V architecture, the Page Template:Mono/styles.css has no content.FENCE instruction is used.
In the case of the x86 architecture, the Page Template:Mono/styles.css has no content.MFENCE, Page Template:Mono/styles.css has no content.LFENCE, and Page Template:Mono/styles.css has no content.SFENCE instructions are used.
Multithreaded programming and memory visibility
Script error: No such module "Labelled list hatnote".
Multithreaded programs usually use synchronization primitives provided by a high-level programming environment—such as Java or .NET—or an application programming interface (API) such as POSIX Threads or Windows API. Synchronization primitives such as mutexes and semaphores are provided to synchronize access to resources from parallel threads of execution. These primitives are usually implemented with the memory barriers required to provide the expected memory visibility semantics. In such environments explicit use of memory barriers is not generally necessary.
Out-of-order execution versus compiler reordering optimizations
Memory barrier instructions address reordering effects only at the hardware level. Compilers may also reorder instructions as part of the program optimization process. Although the effects on parallel program behavior can be similar in both cases, in general, it is necessary to take separate measures to inhibit compiler reordering optimizations for data that may be shared by multiple threads of execution.
In C and C++, the Page Template:Mono/styles.css has no content.volatile keyword was intended to allow C and C++ programs to directly access memory-mapped I/O. Memory-mapped I/O generally requires that the reads and writes specified in source code happen in the exact order specified with no omissions. Omissions or reorderings of reads and writes by the compiler would break the communication between the program and the device accessed by memory-mapped I/O. A C or C++ compiler may not omit reads from and writes to volatile memory locations, nor may it reorder read/writes relative to other such actions for the same volatile location (variable). The keyword Page Template:Mono/styles.css has no content.volatile does not guarantee a memory barrier to enforce cache-consistency. Therefore, the use of Page Template:Mono/styles.css has no content.volatile alone is not sufficient to use a variable for inter-thread communication on all systems and processors.[7]
The C and C++ standards prior to C11 and C++11 do not address multiple threads (or multiple processors),[8] and as such, the usefulness of Page Template:Mono/styles.css has no content.volatile depends on the compiler and hardware. Although Page Template:Mono/styles.css has no content.volatile guarantees that the volatile reads and volatile writes will happen in the exact order specified in the source code, the compiler may generate code (or the CPU may re-order execution) such that a volatile read or write is reordered with regard to non-volatile reads or writes, thus limiting its usefulness as an inter-thread flag or mutex.
See also
Lua error in mw.title.lua at line 404: bad argument #2 to 'title.new' (unrecognized namespace name 'Portal').
References
Page Template:Reflist/styles.css has no content.
- ^ Page Module:Citation/CS1/styles.css has no content.May, Cathy; Silha, Ed; Simpson, Eick; Warren, Hank (1993). The PowerPC Architecture: A Specification for a New Family of RISC Processors. Morgan Kaufmann Publishers. p. 350. ISBN 1-55860-316-6.
- ^ Page Module:Citation/CS1/styles.css has no content.Kacmarcik, Cary (1995). Optimizing PowerPC Code. Addison-Wesley Publishing Company. p. 188. ISBN 0-201-40839-2.
- ^ Page Module:Citation/CS1/styles.css has no content."DMB". Developer.ARM.com. Retrieved January 12, 2025.
- ^ Page Module:Citation/CS1/styles.css has no content."DSB". Developer.ARM.com. Retrieved January 12, 2025.
- ^ Page Module:Citation/CS1/styles.css has no content."ISB". Developer.ARM.com. Retrieved January 12, 2025.
- ^ Page Module:Citation/CS1/styles.css has no content."DMB, DSB, and ISB". Developer.ARM.com. Retrieved January 12, 2025.
- ^ Page Module:Citation/CS1/styles.css has no content.Corbet, Jonathan. "Why the 'Volatile' Type Class Should not Be Used". Kernel.org. Retrieved April 13, 2023.
- ^ Page Module:Citation/CS1/styles.css has no content.Boehm, Hans (June 2005). Threads Cannot Be Implemented As a Library. Proceedings of the 2005 ACM SIGPLAN conference on Programming language design and implementation. Association for Computing Machinery. p. 261. CiteSeerX 10.1.1.308.5939. doi:10.1145/1065010.1065042. ISBN 1595930566.
Further reading
- Page Module:Citation/CS1/styles.css has no content.McKenney, Paul E. (June 30, 2005). "Memory Ordering in Modern Microprocessors, Part I". Linux Journal. Retrieved September 24, 2025.
- Page Module:Citation/CS1/styles.css has no content.McKenney, Paul E. (July 28, 2005). "Memory Ordering in Modern Microprocessors, Part II". Linux Journal. Retrieved September 24, 2025.
External links
- Memory Barriers: a Hardware View for Software Hackers
- LINUX KERNEL MEMORY BARRIERS, kernel/git/torvalds/linux.git
- Handling Memory Ordering in Multithreaded Applications with Oracle Solaris Studio 12 Update 2: Part 1, Compiler Barriers. September 2010. Oracle.
- Handling Memory Ordering in Multithreaded Applications with Oracle Solaris Studio 12 Update 2: Part 2, Memory Barriers and Memory Fences. September 2010. Oracle.
- User-space RCU: Memory-barrier menagerie. LWN.net.
Lua error in package.lua at line 80: module 'Module:Navbox/configuration' not found.