Memory Mappings
Processes can communicate most directly and efficiently with each other through shared memory mappings. A process can map regular files, or special shared memory objects, into its address space using the mmap()
system call. When accessing mapped file contents, the kernel automatically loads the file’s contents into memory. Two processes can create a shared memory mapping of the same file; this means that the kernel points both processes’ page tables to the same physical memory mapping, allowing the processes to communicate directly through shared memory. Processes can also create anonymous memory maps, which are just a region of allocated memory with no underlying file backing; these can be inherited by child processes, similar to open FIFOs vs pipes, except that memory maps are not preserved across calls to exec()
, so anonymous memory mappings can only be shared by related processes running the same program.
Since memory mappings map data into a program’s virtual memory, access to the data in a shared memory map is as fast as accessing any other data in the program’s memory. It requires no additional system calls to access once set up, because access is handled directly by hardware via the memory mapping unit. Since access is not directly mediated by the kernel, data races can occur if two processes simultaneously access the same regions of shared memory. These are the same data races that arise in multithreaded applications, and they are handled using the same techniques and programming toolkit that multithreading uses, such as synchronization and lock-free atomics.