| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> |
| <title>Sharing memory between processes</title> |
| <link rel="stylesheet" href="../../../doc/src/boostbook.css" type="text/css"> |
| <meta name="generator" content="DocBook XSL Stylesheets V1.75.2"> |
| <link rel="home" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset"> |
| <link rel="up" href="../interprocess.html" title="Chapter 9. Boost.Interprocess"> |
| <link rel="prev" href="some_basic_explanations.html" title="Some basic explanations"> |
| <link rel="next" href="offset_ptr.html" title="Mapping Address Independent Pointer: offset_ptr"> |
| </head> |
| <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> |
| <table cellpadding="2" width="100%"><tr> |
| <td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../boost.png"></td> |
| <td align="center"><a href="../../../index.html">Home</a></td> |
| <td align="center"><a href="../../../libs/libraries.htm">Libraries</a></td> |
| <td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> |
| <td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> |
| <td align="center"><a href="../../../more/index.htm">More</a></td> |
| </tr></table> |
| <hr> |
| <div class="spirit-nav"> |
| <a accesskey="p" href="some_basic_explanations.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../interprocess.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="offset_ptr.html"><img src="../../../doc/src/images/next.png" alt="Next"></a> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h2 class="title" style="clear: both"> |
| <a name="interprocess.sharedmemorybetweenprocesses"></a><a class="link" href="sharedmemorybetweenprocesses.html" title="Sharing memory between processes">Sharing memory |
| between processes</a> |
| </h2></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory">Shared |
| memory</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file">Memory Mapped Files</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region">More About Mapped Regions</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations">Limitations When Constructing Objects In Mapped Regions</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.sharedmemory"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory" title="Shared memory">Shared |
| memory</a> |
| </h3></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_what_is">What |
| is shared memory?</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_steps">Creating |
| memory segments that can be shared between processes</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_header">Header</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_creating_shared_memory_segments">Creating |
| shared memory segments</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_mapping_shared_memory_segments">Mapping |
| Shared Memory Segments</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_a_simple_example">A |
| Simple Example</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.emulation">Emulation |
| for systems without shared memory objects</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.removing">Removing |
| shared memory</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.anonymous_shared_memory">Anonymous |
| shared memory for UNIX systems</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.windows_shared_memory">Native |
| windows shared memory</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_what_is"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_what_is" title="What is shared memory?">What |
| is shared memory?</a> |
| </h4></div></div></div> |
| <p> |
| Shared memory is the fastest interprocess communication mechanism. The |
| operating system maps a memory segment in the address space of several |
| processes, so that several processes can read and write in that memory |
| segment without calling operating system functions. However, we need some |
| kind of synchronization between processes that read and write shared memory. |
| </p> |
| <p> |
| Consider what happens when a server process wants to send an HTML file |
| to a client process that resides in the same machine using network mechanisms: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"> |
| <li class="listitem"> |
| The server must read the file to memory and pass it to the network |
| functions, that copy that memory to the OS's internal memory. |
| </li> |
| <li class="listitem"> |
| The client uses the network functions to copy the data from the OS's |
| internal memory to its own memory. |
| </li> |
| </ul></div> |
| <p> |
| As we can see, there are two copies, one from memory to the network and |
| another one from the network to memory. And those copies are made using |
| operating system calls that normally are expensive. Shared memory avoids |
| this overhead, but we need to synchronize both processes: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"> |
| <li class="listitem"> |
| The server maps a shared memory in its address space and also gets |
| access to a synchronization mechanism. The server obtains exclusive |
| access to the memory using the synchronization mechanism and copies |
| the file to memory. |
| </li> |
| <li class="listitem"> |
| The client maps the shared memory in its address space. Waits until |
| the server releases the exclusive access and uses the data. |
| </li> |
| </ul></div> |
| <p> |
| Using shared memory, we can avoid two data copies, but we have to synchronize |
| the access to the shared memory segment. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_steps"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_steps" title="Creating memory segments that can be shared between processes">Creating |
| memory segments that can be shared between processes</a> |
| </h4></div></div></div> |
| <p> |
| To use shared memory, we have to perform 2 basic steps: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"> |
| <li class="listitem"> |
| Request to the operating system a memory segment that can be shared |
| between processes. The user can create/destroy/open this memory using |
| a <span class="bold"><strong>shared memory object</strong></span>: <span class="emphasis"><em>An |
| object that represents memory that can be mapped concurrently into |
| the address space of more than one process.</em></span>. |
| </li> |
| <li class="listitem"> |
| Associate a part of that memory or the whole memory with the address |
| space of the calling process. The operating system looks for a big |
| enough memory address range in the calling process' address space and |
| marks that address range as an special range. Changes in that address |
| range are automatically seen by other process that also have mapped |
| the same shared memory object. |
| </li> |
| </ul></div> |
| <p> |
| Once the two steps have been successfully completed, the process can start |
| writing to and reading from the address space to send to and receive data |
| from other processes. Now, let's see how can we do this using <span class="bold"><strong>Boost.Interprocess</strong></span>: |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_header"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_header" title="Header">Header</a> |
| </h4></div></div></div> |
| <p> |
| To manage shared memory, you just need to include the following header: |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">shared_memory_object</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_creating_shared_memory_segments"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_creating_shared_memory_segments" title="Creating shared memory segments">Creating |
| shared memory segments</a> |
| </h4></div></div></div> |
| <p> |
| As we've mentioned we have to use the <code class="computeroutput"><span class="identifier">shared_memory_object</span></code> |
| class to create, open and destroy shared memory segments that can be mapped |
| by several processes. We can specify the access mode of that shared memory |
| object (read only or read-write), just as if it was a file: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> |
| Create a shared memory segment. Throws if already created: |
| </li></ul></div> |
| <pre class="programlisting"><span class="keyword">using</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">;</span> |
| <span class="identifier">shared_memory_object</span> <span class="identifier">shm_obj</span> |
| <span class="special">(</span><span class="identifier">create_only</span> <span class="comment">//only create |
| </span> <span class="special">,</span><span class="string">"shared_memory"</span> <span class="comment">//name |
| </span> <span class="special">,</span><span class="identifier">read_write</span> <span class="comment">//read-write mode |
| </span> <span class="special">);</span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> |
| To open or create a shared memory segment: |
| </li></ul></div> |
| <pre class="programlisting"><span class="keyword">using</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">;</span> |
| <span class="identifier">shared_memory_object</span> <span class="identifier">shm_obj</span> |
| <span class="special">(</span><span class="identifier">open_or_create</span> <span class="comment">//open or create |
| </span> <span class="special">,</span><span class="string">"shared_memory"</span> <span class="comment">//name |
| </span> <span class="special">,</span><span class="identifier">read_only</span> <span class="comment">//read-only mode |
| </span> <span class="special">);</span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> |
| To only open a shared memory segment. Throws if does not exist: |
| </li></ul></div> |
| <pre class="programlisting"><span class="keyword">using</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">;</span> |
| <span class="identifier">shared_memory_object</span> <span class="identifier">shm_obj</span> |
| <span class="special">(</span><span class="identifier">open_only</span> <span class="comment">//only open |
| </span> <span class="special">,</span><span class="string">"shared_memory"</span> <span class="comment">//name |
| </span> <span class="special">,</span><span class="identifier">read_write</span> <span class="comment">//read-write mode |
| </span> <span class="special">);</span> |
| </pre> |
| <p> |
| When a shared memory object is created, its size is 0. To set the size |
| of the shared memory, the user must use the <code class="computeroutput"><span class="identifier">truncate</span></code> |
| function call, in a shared memory that has been opened with read-write |
| attributes: |
| </p> |
| <pre class="programlisting"><span class="identifier">shm_obj</span><span class="special">.</span><span class="identifier">truncate</span><span class="special">(</span><span class="number">10000</span><span class="special">);</span> |
| </pre> |
| <p> |
| As shared memory has kernel or filesystem persistence, the user must explicitly |
| destroy it. The <code class="computeroutput"><span class="identifier">remove</span></code> |
| operation might fail returning false if the shared memory does not exist, |
| the file is open or the file is still memory mapped by other processes: |
| </p> |
| <pre class="programlisting"><span class="keyword">using</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">;</span> |
| <span class="identifier">shared_memory_object</span><span class="special">::</span><span class="identifier">remove</span><span class="special">(</span><span class="string">"shared_memory"</span><span class="special">);</span> |
| </pre> |
| <p> |
| For more details regarding <code class="computeroutput"><span class="identifier">shared_memory_object</span></code> |
| see the <code class="computeroutput"><a class="link" href="../boost/interprocess/shared_memory_object.html" title="Class shared_memory_object">boost::interprocess::shared_memory_object</a></code> |
| class reference. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_mapping_shared_memory_segments"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_mapping_shared_memory_segments" title="Mapping Shared Memory Segments">Mapping |
| Shared Memory Segments</a> |
| </h4></div></div></div> |
| <p> |
| Once created or opened, a process just has to map the shared memory object |
| in the process' address space. The user can map the whole shared memory |
| or just part of it. The mapping process is done using the <code class="computeroutput"><span class="identifier">mapped_region</span></code> class. The class represents |
| a memory region that has been mapped from a shared memory or from other |
| devices that have also mapping capabilities (for example, files). A <code class="computeroutput"><span class="identifier">mapped_region</span></code> can be created from any |
| <code class="computeroutput"><span class="identifier">memory_mappable</span></code> object |
| and as you might imagine, <code class="computeroutput"><span class="identifier">shared_memory_object</span></code> |
| is a <code class="computeroutput"><span class="identifier">memory_mappable</span></code> object: |
| </p> |
| <pre class="programlisting"><span class="keyword">using</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">ShmSize</span> <span class="special">=</span> <span class="special">...</span> |
| |
| <span class="comment">//Map the second half of the memory |
| </span><span class="identifier">mapped_region</span> <span class="identifier">region</span> |
| <span class="special">(</span> <span class="identifier">shm</span> <span class="comment">//Memory-mappable object |
| </span> <span class="special">,</span> <span class="identifier">read_write</span> <span class="comment">//Access mode |
| </span> <span class="special">,</span> <span class="identifier">ShmSize</span><span class="special">/</span><span class="number">2</span> <span class="comment">//Offset from the beginning of shm |
| </span> <span class="special">,</span> <span class="identifier">ShmSize</span><span class="special">-</span><span class="identifier">ShmSize</span><span class="special">/</span><span class="number">2</span> <span class="comment">//Length of the region |
| </span> <span class="special">);</span> |
| |
| <span class="comment">//Get the address of the region |
| </span><span class="identifier">region</span><span class="special">.</span><span class="identifier">get_address</span><span class="special">();</span> |
| |
| <span class="comment">//Get the size of the region |
| </span><span class="identifier">region</span><span class="special">.</span><span class="identifier">get_size</span><span class="special">();</span> |
| </pre> |
| <p> |
| The user can specify the offset from the mappable object where the mapped |
| region should start and the size of the mapped region. If no offset or |
| size is specified, the whole mappable object (in this case, shared memory) |
| is mapped. If the offset is specified, but not the size, the mapped region |
| covers from the offset until the end of the mappable object. |
| </p> |
| <p> |
| For more details regarding <code class="computeroutput"><span class="identifier">mapped_region</span></code> |
| see the <code class="computeroutput"><a class="link" href="../boost/interprocess/mapped_region.html" title="Class mapped_region">boost::interprocess::mapped_region</a></code> |
| class reference. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_a_simple_example"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.shared_memory_a_simple_example" title="A Simple Example">A |
| Simple Example</a> |
| </h4></div></div></div> |
| <p> |
| Let's see a simple example of shared memory use. A server process creates |
| a shared memory object, maps it and initializes all the bytes to a value. |
| After that, a client process opens the shared memory, maps it, and checks |
| that the data is correctly initialized: |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">shared_memory_object</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">mapped_region</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">cstring</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">cstdlib</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">string</span><span class="special">></span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">argc</span><span class="special">,</span> <span class="keyword">char</span> <span class="special">*</span><span class="identifier">argv</span><span class="special">[])</span> |
| <span class="special">{</span> |
| <span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">;</span> |
| |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">argc</span> <span class="special">==</span> <span class="number">1</span><span class="special">){</span> <span class="comment">//Parent process |
| </span> <span class="comment">//Remove shared memory on construction and destruction |
| </span> <span class="keyword">struct</span> <span class="identifier">shm_remove</span> |
| <span class="special">{</span> |
| <span class="identifier">shm_remove</span><span class="special">()</span> <span class="special">{</span> <span class="identifier">shared_memory_object</span><span class="special">::</span><span class="identifier">remove</span><span class="special">(</span><span class="string">"MySharedMemory"</span><span class="special">);</span> <span class="special">}</span> |
| <span class="special">~</span><span class="identifier">shm_remove</span><span class="special">(){</span> <span class="identifier">shared_memory_object</span><span class="special">::</span><span class="identifier">remove</span><span class="special">(</span><span class="string">"MySharedMemory"</span><span class="special">);</span> <span class="special">}</span> |
| <span class="special">}</span> <span class="identifier">remover</span><span class="special">;</span> |
| |
| <span class="comment">//Create a shared memory object. |
| </span> <span class="identifier">shared_memory_object</span> <span class="identifier">shm</span> <span class="special">(</span><span class="identifier">create_only</span><span class="special">,</span> <span class="string">"MySharedMemory"</span><span class="special">,</span> <span class="identifier">read_write</span><span class="special">);</span> |
| |
| <span class="comment">//Set size |
| </span> <span class="identifier">shm</span><span class="special">.</span><span class="identifier">truncate</span><span class="special">(</span><span class="number">1000</span><span class="special">);</span> |
| |
| <span class="comment">//Map the whole shared memory in this process |
| </span> <span class="identifier">mapped_region</span> <span class="identifier">region</span><span class="special">(</span><span class="identifier">shm</span><span class="special">,</span> <span class="identifier">read_write</span><span class="special">);</span> |
| |
| <span class="comment">//Write all the memory to 1 |
| </span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">memset</span><span class="special">(</span><span class="identifier">region</span><span class="special">.</span><span class="identifier">get_address</span><span class="special">(),</span> <span class="number">1</span><span class="special">,</span> <span class="identifier">region</span><span class="special">.</span><span class="identifier">get_size</span><span class="special">());</span> |
| |
| <span class="comment">//Launch child process |
| </span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">s</span><span class="special">(</span><span class="identifier">argv</span><span class="special">[</span><span class="number">0</span><span class="special">]);</span> <span class="identifier">s</span> <span class="special">+=</span> <span class="string">" child "</span><span class="special">;</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="number">0</span> <span class="special">!=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">system</span><span class="special">(</span><span class="identifier">s</span><span class="special">.</span><span class="identifier">c_str</span><span class="special">()))</span> |
| <span class="keyword">return</span> <span class="number">1</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="keyword">else</span><span class="special">{</span> |
| <span class="comment">//Open already created shared memory object. |
| </span> <span class="identifier">shared_memory_object</span> <span class="identifier">shm</span> <span class="special">(</span><span class="identifier">open_only</span><span class="special">,</span> <span class="string">"MySharedMemory"</span><span class="special">,</span> <span class="identifier">read_only</span><span class="special">);</span> |
| |
| <span class="comment">//Map the whole shared memory in this process |
| </span> <span class="identifier">mapped_region</span> <span class="identifier">region</span><span class="special">(</span><span class="identifier">shm</span><span class="special">,</span> <span class="identifier">read_only</span><span class="special">);</span> |
| |
| <span class="comment">//Check that memory was initialized to 1 |
| </span> <span class="keyword">char</span> <span class="special">*</span><span class="identifier">mem</span> <span class="special">=</span> <span class="keyword">static_cast</span><span class="special"><</span><span class="keyword">char</span><span class="special">*>(</span><span class="identifier">region</span><span class="special">.</span><span class="identifier">get_address</span><span class="special">());</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special"><</span> <span class="identifier">region</span><span class="special">.</span><span class="identifier">get_size</span><span class="special">();</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="keyword">if</span><span class="special">(*</span><span class="identifier">mem</span><span class="special">++</span> <span class="special">!=</span> <span class="number">1</span><span class="special">)</span> |
| <span class="keyword">return</span> <span class="number">1</span><span class="special">;</span> <span class="comment">//Error checking memory |
| </span> <span class="special">}</span> |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.sharedmemory.emulation"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.emulation" title="Emulation for systems without shared memory objects">Emulation |
| for systems without shared memory objects</a> |
| </h4></div></div></div> |
| <p> |
| <span class="bold"><strong>Boost.Interprocess</strong></span> provides portable shared |
| memory in terms of POSIX semantics. Some operating systems don't support |
| shared memory as defined by POSIX: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"> |
| <li class="listitem"> |
| Windows operating systems provide shared memory using memory backed |
| by the paging file but the lifetime semantics are different from the |
| ones defined by POSIX (see <a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.windows_shared_memory" title="Native windows shared memory">Native |
| windows shared memory</a> section for more information). |
| </li> |
| <li class="listitem"> |
| Some UNIX systems don't fully support POSIX shared memory objects at |
| all. |
| </li> |
| </ul></div> |
| <p> |
| In those platforms, shared memory is emulated with mapped files created |
| in a "boost_interprocess" folder created in a temporary files |
| directory. In Windows platforms, if "Common AppData" key is present |
| in the registry, "boost_interprocess" folder is created in that |
| directory (in XP usually "C:\Documents and Settings\All Users\Application |
| Data" and in Vista "C:\ProgramData"). For Windows platforms |
| without that registry key and Unix systems, shared memory is created in |
| the system temporary files directory ("/tmp" or similar). |
| </p> |
| <p> |
| Because of this emulation, shared memory has filesystem lifetime in some |
| of those systems. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.sharedmemory.removing"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.removing" title="Removing shared memory">Removing |
| shared memory</a> |
| </h4></div></div></div> |
| <p> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/shared_memory_object.html" title="Class shared_memory_object">shared_memory_object</a></code> |
| provides a static <code class="computeroutput"><span class="identifier">remove</span></code> |
| function to remove a shared memory objects. |
| </p> |
| <p> |
| This function <span class="bold"><strong>can</strong></span> fail if the shared memory |
| objects does not exist or it's opened by another process. Note that this |
| function is similar to the standard C <code class="computeroutput"><span class="keyword">int</span> |
| <span class="identifier">remove</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">char</span> <span class="special">*</span><span class="identifier">path</span><span class="special">)</span></code> function. In UNIX systems, <code class="computeroutput"><span class="identifier">shared_memory_object</span><span class="special">::</span><span class="identifier">remove</span></code> calls <code class="computeroutput"><span class="identifier">shm_unlink</span></code>: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"> |
| <li class="listitem"> |
| The function will remove the name of the shared memory object named |
| by the string pointed to by name. |
| </li> |
| <li class="listitem"> |
| If one or more references to the shared memory object exist when is |
| unlinked, the name will be removed before the function returns, but |
| the removal of the memory object contents will be postponed until all |
| open and map references to the shared memory object have been removed. |
| </li> |
| <li class="listitem"> |
| Even if the object continues to exist after the last function call, |
| reuse of the name will subsequently cause the creation of a <code class="computeroutput"><a class="link" href="../boost/interprocess/shared_memory_object.html" title="Class shared_memory_object">boost::interprocess::shared_memory_object</a></code> |
| instance to behave as if no shared memory object of this name exists |
| (that is, trying to open an object with that name will fail and an |
| object of the same name can be created again). |
| </li> |
| </ul></div> |
| <p> |
| In Windows operating systems, current version supports an usually acceptable |
| emulation of the UNIX unlink behaviour: the file is renamed with a random |
| name and marked as <span class="emphasis"><em>to be deleted when the last open handle is |
| closed</em></span>. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.sharedmemory.anonymous_shared_memory"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.anonymous_shared_memory" title="Anonymous shared memory for UNIX systems">Anonymous |
| shared memory for UNIX systems</a> |
| </h4></div></div></div> |
| <p> |
| Creating a shared memory segment and mapping it can be a bit tedious when |
| several processes are involved. When processes are related via <code class="computeroutput"><span class="identifier">fork</span><span class="special">()</span></code> |
| operating system call in UNIX systems a simpler method is available using |
| anonymous shared memory. |
| </p> |
| <p> |
| This feature has been implemented in UNIX systems mapping the device <code class="computeroutput"><span class="special">\</span><span class="identifier">dev</span><span class="special">\</span><span class="identifier">zero</span></code> |
| or just using the <code class="computeroutput"><span class="identifier">MAP_ANONYMOUS</span></code> |
| in a POSIX conformant <code class="computeroutput"><span class="identifier">mmap</span></code> |
| system call. |
| </p> |
| <p> |
| This feature is wrapped in <span class="bold"><strong>Boost.Interprocess</strong></span> |
| using the <code class="computeroutput"><span class="identifier">anonymous_shared_memory</span><span class="special">()</span></code> function, which returns a <code class="computeroutput"><span class="identifier">mapped_region</span></code> object holding an anonymous |
| shared memory segment that can be shared by related processes. |
| </p> |
| <p> |
| Here is an example: |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">anonymous_shared_memory</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">mapped_region</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">cstring</span><span class="special">></span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span> <span class="special">()</span> |
| <span class="special">{</span> |
| <span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">;</span> |
| <span class="keyword">try</span><span class="special">{</span> |
| <span class="comment">//Create an anonymous shared memory segment with size 1000 |
| </span> <span class="identifier">mapped_region</span> <span class="identifier">region</span><span class="special">(</span><span class="identifier">anonymous_shared_memory</span><span class="special">(</span><span class="number">1000</span><span class="special">));</span> |
| |
| <span class="comment">//Write all the memory to 1 |
| </span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">memset</span><span class="special">(</span><span class="identifier">region</span><span class="special">.</span><span class="identifier">get_address</span><span class="special">(),</span> <span class="number">1</span><span class="special">,</span> <span class="identifier">region</span><span class="special">.</span><span class="identifier">get_size</span><span class="special">());</span> |
| |
| <span class="comment">//The segment is unmapped when "region" goes out of scope |
| </span> <span class="special">}</span> |
| <span class="keyword">catch</span><span class="special">(</span><span class="identifier">interprocess_exception</span> <span class="special">&</span><span class="identifier">ex</span><span class="special">){</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">ex</span><span class="special">.</span><span class="identifier">what</span><span class="special">()</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="keyword">return</span> <span class="number">1</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| Once the segment is created, a <code class="computeroutput"><span class="identifier">fork</span><span class="special">()</span></code> call can be used so that <code class="computeroutput"><span class="identifier">region</span></code> is used to communicate two related |
| processes. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.sharedmemory.windows_shared_memory"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory.windows_shared_memory" title="Native windows shared memory">Native |
| windows shared memory</a> |
| </h4></div></div></div> |
| <p> |
| Windows operating system also offers shared memory, but the lifetime of |
| this shared memory is very different to kernel or filesystem lifetime. |
| The shared memory is created backed by the pagefile and it's automatically |
| destroyed when the last process attached to the shared memory is destroyed. |
| </p> |
| <p> |
| Because of this reason, there is no effective way to simulate kernel or |
| filesystem persistence using native windows shared memory and <span class="bold"><strong>Boost.Interprocess</strong></span> emulates shared memory using |
| memory mapped files. This assures portability between POSIX and Windows |
| operating systems. |
| </p> |
| <p> |
| However, accessing native windows shared memory is a common request of |
| <span class="bold"><strong>Boost.Interprocess</strong></span> users because they |
| want to access to shared memory created with other process that don't use |
| <span class="bold"><strong>Boost.Interprocess</strong></span>. In order to manage |
| the native windows shared memory <span class="bold"><strong>Boost.Interprocess</strong></span> |
| offers the <code class="computeroutput"><a class="link" href="../boost/interprocess/windows_shared_memory.html" title="Class windows_shared_memory">windows_shared_memory</a></code> |
| class. |
| </p> |
| <p> |
| Windows shared memory creation is a bit different from portable shared |
| memory creation: the size of the segment must be specified when creating |
| the object and can't be specified through <code class="computeroutput"><span class="identifier">truncate</span></code> |
| like with the shared memory object. |
| </p> |
| <p> |
| Take in care that when the last process attached to a shared memory is |
| destroyed <span class="bold"><strong>the shared memory is destroyed</strong></span> |
| so there is <span class="bold"><strong>no persistency</strong></span> with native |
| windows shared memory. Native windows shared memory has also another limitation: |
| a process can open and map the whole shared memory created by another process |
| but it can't know which is the size of that memory. This limitation is |
| imposed by the Windows API so the user must somehow transmit the size of |
| the segment to processes opening the segment. |
| </p> |
| <p> |
| Sharing memory between services and user applications is also different. |
| To share memory between services and user applications the name of the |
| shared memory must start with the global namespace prefix <code class="computeroutput"><span class="string">"Global\\"</span></code>. This global namespace |
| enables processes on multiple client sessions to communicate with a service |
| application. The server component can create the shared memory in the global |
| namespace. Then a client session can use the "Global" prefix |
| to open that memory. |
| </p> |
| <p> |
| The creation of a shared memory object in the global namespace from a session other than |
| session zero is a privileged operation. |
| </p> |
| <p> |
| Let's repeat the same example presented for the portable shared memory object: |
| A server process creates a |
| shared memory object, maps it and initializes all the bytes to a value. After that, |
| a client process opens the shared memory, maps it, and checks |
| that the data is correctly initialized. Take in care that <span class="bold"><strong>if the server exits before |
| the client connects to the shared memory the client connection will fail</strong></span>, because |
| the shared memory segment is destroyed when no proces is attached to the memory. |
| </p> |
| <p> |
| This is the server process: |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">windows_shared_memory</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">mapped_region</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">cstring</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">cstdlib</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">string</span><span class="special">></span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">argc</span><span class="special">,</span> <span class="keyword">char</span> <span class="special">*</span><span class="identifier">argv</span><span class="special">[])</span> |
| <span class="special">{</span> |
| <span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">;</span> |
| |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">argc</span> <span class="special">==</span> <span class="number">1</span><span class="special">){</span> <span class="comment">//Parent process |
| </span> <span class="comment">//Create a native windows shared memory object. |
| </span> <span class="identifier">windows_shared_memory</span> <span class="identifier">shm</span> <span class="special">(</span><span class="identifier">create_only</span><span class="special">,</span> <span class="string">"MySharedMemory"</span><span class="special">,</span> <span class="identifier">read_write</span><span class="special">,</span> <span class="number">1000</span><span class="special">);</span> |
| |
| <span class="comment">//Map the whole shared memory in this process |
| </span> <span class="identifier">mapped_region</span> <span class="identifier">region</span><span class="special">(</span><span class="identifier">shm</span><span class="special">,</span> <span class="identifier">read_write</span><span class="special">);</span> |
| |
| <span class="comment">//Write all the memory to 1 |
| </span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">memset</span><span class="special">(</span><span class="identifier">region</span><span class="special">.</span><span class="identifier">get_address</span><span class="special">(),</span> <span class="number">1</span><span class="special">,</span> <span class="identifier">region</span><span class="special">.</span><span class="identifier">get_size</span><span class="special">());</span> |
| |
| <span class="comment">//Launch child process |
| </span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">s</span><span class="special">(</span><span class="identifier">argv</span><span class="special">[</span><span class="number">0</span><span class="special">]);</span> <span class="identifier">s</span> <span class="special">+=</span> <span class="string">" child "</span><span class="special">;</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="number">0</span> <span class="special">!=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">system</span><span class="special">(</span><span class="identifier">s</span><span class="special">.</span><span class="identifier">c_str</span><span class="special">()))</span> |
| <span class="keyword">return</span> <span class="number">1</span><span class="special">;</span> |
| <span class="comment">//windows_shared_memory is destroyed when the last attached process dies... |
| </span> <span class="special">}</span> |
| <span class="keyword">else</span><span class="special">{</span> |
| <span class="comment">//Open already created shared memory object. |
| </span> <span class="identifier">windows_shared_memory</span> <span class="identifier">shm</span> <span class="special">(</span><span class="identifier">open_only</span><span class="special">,</span> <span class="string">"MySharedMemory"</span><span class="special">,</span> <span class="identifier">read_only</span><span class="special">);</span> |
| |
| <span class="comment">//Map the whole shared memory in this process |
| </span> <span class="identifier">mapped_region</span> <span class="identifier">region</span><span class="special">(</span><span class="identifier">shm</span><span class="special">,</span> <span class="identifier">read_only</span><span class="special">);</span> |
| |
| <span class="comment">//Check that memory was initialized to 1 |
| </span> <span class="keyword">char</span> <span class="special">*</span><span class="identifier">mem</span> <span class="special">=</span> <span class="keyword">static_cast</span><span class="special"><</span><span class="keyword">char</span><span class="special">*>(</span><span class="identifier">region</span><span class="special">.</span><span class="identifier">get_address</span><span class="special">());</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special"><</span> <span class="identifier">region</span><span class="special">.</span><span class="identifier">get_size</span><span class="special">();</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="keyword">if</span><span class="special">(*</span><span class="identifier">mem</span><span class="special">++</span> <span class="special">!=</span> <span class="number">1</span><span class="special">)</span> |
| <span class="keyword">return</span> <span class="number">1</span><span class="special">;</span> <span class="comment">//Error checking memory |
| </span> <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| As we can see, native windows shared memory needs synchronization to make sure |
| that the shared memory won't be destroyed before the client is launched. |
| </p> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_file"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file" title="Memory Mapped Files">Memory Mapped Files</a> |
| </h3></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_what_is">What is a memory mapped file?</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_steps">Using mapped files</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_header">Header</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_creating_file">Creating a file mapping</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_mapping_regions">Mapping File's Contents In Memory</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_a_simple_example">A Simple Example</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_what_is"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_what_is" title="What is a memory mapped file?">What is a memory mapped file?</a> |
| </h4></div></div></div> |
| <p> |
| File mapping is the association of a file's contents with a portion of the address space |
| of a process. The system creates a file mapping to associate the file and the address |
| space of the process. A mapped region is the portion of address space that the process |
| uses to access the file's contents. A single file mapping can have several mapped regions, |
| so that the user can associate parts of the file with the address space of the process |
| without mapping the entire file in the address space, since the file can be bigger |
| than the whole address space of the process (a 9GB DVD image file in a usual 32 |
| bit systems). Processes read from and write to |
| the file using pointers, just like with dynamic memory. File mapping has the following |
| advantages: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"> |
| <li class="listitem"> |
| Uniform resource use. Files and memory can be treated using the same functions. |
| |
| </li> |
| <li class="listitem"> |
| Automatic file data synchronization and cache from the OS. |
| |
| </li> |
| <li class="listitem"> |
| Reuse of C++ utilities (STL containers, algorithms) in files. |
| |
| </li> |
| <li class="listitem"> |
| Shared memory between two or more applications. |
| |
| </li> |
| <li class="listitem"> |
| Allows efficient work with a large files, without mapping the whole file into memory |
| |
| </li> |
| <li class="listitem"> |
| If several processes use the same file mapping to create mapped regions of a file, each |
| process' views contain identical copies of the file on disk. |
| |
| </li> |
| </ul></div> |
| <p> |
| File mapping is not only used for interprocess communication, it can be used also to |
| simplify file usage, so the user does not need to use file-management functions to |
| write the file. The user just writes data to the process memory, and the operating |
| systems dumps the data to the file. |
| </p> |
| <p> |
| When two processes map the same file in memory, the memory that one process writes is |
| seen by another process, so memory mapped files can be used as an interprocess |
| communication mechanism. We can say that memory-mapped files offer the same interprocess |
| communication services as shared memory with the addition of filesystem persistence. |
| However, as the operating system has to synchronize the file contents with the memory |
| contents, memory-mapped files are not as fast as shared memory. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_steps"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_steps" title="Using mapped files">Using mapped files</a> |
| </h4></div></div></div> |
| <p> |
| To use memory-mapped files, we have to perform 2 basic steps: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"> |
| <li class="listitem"> |
| Create a mappable object that represent an already created file of the |
| filesystem. This object will be used to create multiple mapped regions of the |
| the file. |
| |
| </li> |
| <li class="listitem"> |
| Associate the whole file or parts of the file with the address space of the |
| calling process. The operating system looks for a big enough memory address range |
| in the calling process' address space and marks that address range as an |
| special range. Changes in that address range are automatically seen |
| by other process that also have mapped the same file and those changes |
| are also transferred to the disk automatically. |
| |
| </li> |
| </ul></div> |
| <p> |
| Once the two steps have been successfully completed, the process can start writing to |
| and reading from the address space to send to and receive data from other processes |
| and synchronize the file's contents with the changes made to the mapped region. |
| Now, let's see how can we do this using <span class="bold"><strong>Boost.Interprocess</strong></span>: |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_header"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_header" title="Header">Header</a> |
| </h4></div></div></div> |
| <p> |
| To manage mapped files, you just need to include the following header: |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">file_mapping</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_creating_file"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_creating_file" title="Creating a file mapping">Creating a file mapping</a> |
| </h4></div></div></div> |
| <p> |
| First, we have to link a file's contents with the process' address space. To do |
| this, we have to create a mappable object that represents that file. This is |
| achieved in <span class="bold"><strong>Boost.Interprocess</strong></span> creating a <code class="computeroutput"><span class="identifier">file_mapping</span></code> object: |
| </p> |
| <pre class="programlisting"><span class="keyword">using</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">;</span> |
| <span class="identifier">file_mapping</span> <span class="identifier">m_file</span> |
| <span class="special">(</span><span class="string">"/usr/home/file"</span> <span class="comment">//filename |
| </span> <span class="special">,</span><span class="identifier">read_write</span> <span class="comment">//read-write mode |
| </span> <span class="special">);</span> |
| </pre> |
| <p> |
| Now we can use the newly created object to create mapped regions. For more details |
| regarding this class see the |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/file_mapping.html" title="Class file_mapping">boost::interprocess::file_mapping</a></code> class reference. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_mapping_regions"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_mapping_regions" title="Mapping File's Contents In Memory">Mapping File's Contents In Memory</a> |
| </h4></div></div></div> |
| <p> |
| After creating a file mapping, a process just has to map the shared memory in the |
| process' address space. The user can map the whole shared memory or just part of it. |
| The mapping process is done using the <code class="computeroutput"><span class="identifier">mapped_region</span></code> class. as we have said before |
| The class represents a memory region that has been mapped from a shared memory or from other |
| devices that have also mapping capabilities: |
| </p> |
| <pre class="programlisting"><span class="keyword">using</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">FileSize</span> <span class="special">=</span> <span class="special">...</span> |
| |
| <span class="comment">//Map the second half of the file |
| </span><span class="identifier">mapped_region</span> <span class="identifier">region</span> |
| <span class="special">(</span> <span class="identifier">m_file</span> <span class="comment">//Memory-mappable object |
| </span> <span class="special">,</span> <span class="identifier">read_write</span> <span class="comment">//Access mode |
| </span> <span class="special">,</span> <span class="identifier">FileSize</span><span class="special">/</span><span class="number">2</span> <span class="comment">//Offset from the beginning of shm |
| </span> <span class="special">,</span> <span class="identifier">FileSize</span><span class="special">-</span><span class="identifier">FileSize</span><span class="special">/</span><span class="number">2</span> <span class="comment">//Length of the region |
| </span> <span class="special">);</span> |
| |
| <span class="comment">//Get the address of the region |
| </span><span class="identifier">region</span><span class="special">.</span><span class="identifier">get_address</span><span class="special">();</span> |
| |
| <span class="comment">//Get the size of the region |
| </span><span class="identifier">region</span><span class="special">.</span><span class="identifier">get_size</span><span class="special">();</span> |
| </pre> |
| <p> |
| The user can specify the offset from the file where the mapped region |
| should start and the size of the mapped region. If no offset or size is specified, |
| the whole file is mapped. If the offset is specified, but not the size, |
| the mapped region covers from the offset until the end of the file. |
| </p> |
| <p> |
| If several processes map the same file, and a process modifies a memory range |
| from a mapped region that is also mapped by other process, the changes are |
| inmedially visible to other processes. However, the file contents on disk are |
| not updated immediately, since that would hurt performance (writing to disk |
| is several times slower than writing to memory). If the user wants to make sure |
| that file's contents have been updated, it can flush a range from the view to disk. |
| When the function returns, the flushing process has startd but there is not guarantee that |
| all data has been written to disk: |
| </p> |
| <pre class="programlisting"><span class="comment">//Flush the whole region |
| </span><span class="identifier">region</span><span class="special">.</span><span class="identifier">flush</span><span class="special">();</span> |
| |
| <span class="comment">//Flush from an offset until the end of the region |
| </span><span class="identifier">region</span><span class="special">.</span><span class="identifier">flush</span><span class="special">(</span><span class="identifier">offset</span><span class="special">);</span> |
| |
| <span class="comment">//Flush a memory range starting on an offset |
| </span><span class="identifier">region</span><span class="special">.</span><span class="identifier">flush</span><span class="special">(</span><span class="identifier">offset</span><span class="special">,</span> <span class="identifier">size</span><span class="special">);</span> |
| </pre> |
| <p> |
| Remember that the offset is <span class="bold"><strong>not</strong></span> an offset on the file, but an offset in the |
| mapped region. If a region covers the second half of a file and flushes the |
| whole region, only the half of the file is guaranteed to have been flushed. |
| </p> |
| <p> |
| For more details regarding <code class="computeroutput"><span class="identifier">mapped_region</span></code> see the |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/mapped_region.html" title="Class mapped_region">boost::interprocess::mapped_region</a></code> class reference. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_a_simple_example"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file.mapped_file_a_simple_example" title="A Simple Example">A Simple Example</a> |
| </h4></div></div></div> |
| <p> |
| Let's reproduce the same example described in the shared memory section, using |
| memory mapped files. A server process creates a shared |
| memory segment, maps it and initializes all the bytes to a value. After that, |
| a client process opens the shared memory, maps it, and checks |
| that the data is correctly initialized:: |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">file_mapping</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">mapped_region</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">fstream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">string</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">vector</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">cstring</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">cstddef</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">cstdlib</span><span class="special">></span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">argc</span><span class="special">,</span> <span class="keyword">char</span> <span class="special">*</span><span class="identifier">argv</span><span class="special">[])</span> |
| <span class="special">{</span> |
| <span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">;</span> |
| <span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">FileSize</span> <span class="special">=</span> <span class="number">10000</span><span class="special">;</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">argc</span> <span class="special">==</span> <span class="number">1</span><span class="special">){</span> <span class="comment">//Parent process executes this |
| </span> <span class="special">{</span> <span class="comment">//Create a file |
| </span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">filebuf</span> <span class="identifier">fbuf</span><span class="special">;</span> |
| <span class="identifier">fbuf</span><span class="special">.</span><span class="identifier">open</span><span class="special">(</span><span class="string">"file.bin"</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ios_base</span><span class="special">::</span><span class="identifier">in</span> <span class="special">|</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ios_base</span><span class="special">::</span><span class="identifier">out</span> |
| <span class="special">|</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ios_base</span><span class="special">::</span><span class="identifier">trunc</span> <span class="special">|</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ios_base</span><span class="special">::</span><span class="identifier">binary</span><span class="special">);</span> |
| <span class="comment">//Set the size |
| </span> <span class="identifier">fbuf</span><span class="special">.</span><span class="identifier">pubseekoff</span><span class="special">(</span><span class="identifier">FileSize</span><span class="special">-</span><span class="number">1</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ios_base</span><span class="special">::</span><span class="identifier">beg</span><span class="special">);</span> |
| <span class="identifier">fbuf</span><span class="special">.</span><span class="identifier">sputc</span><span class="special">(</span><span class="number">0</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="comment">//Remove file on exit |
| </span> <span class="keyword">struct</span> <span class="identifier">file_remove</span> |
| <span class="special">{</span> |
| <span class="special">~</span><span class="identifier">file_remove</span> <span class="special">(){</span> <span class="identifier">file_mapping</span><span class="special">::</span><span class="identifier">remove</span><span class="special">(</span><span class="string">"file.bin"</span><span class="special">);</span> <span class="special">}</span> |
| <span class="special">}</span> <span class="identifier">destroy_on_exit</span><span class="special">;</span> |
| |
| <span class="comment">//Create a file mapping |
| </span> <span class="identifier">file_mapping</span> <span class="identifier">m_file</span><span class="special">(</span><span class="string">"file.bin"</span><span class="special">,</span> <span class="identifier">read_write</span><span class="special">);</span> |
| |
| <span class="comment">//Map the whole file with read-write permissions in this process |
| </span> <span class="identifier">mapped_region</span> <span class="identifier">region</span><span class="special">(</span><span class="identifier">m_file</span><span class="special">,</span> <span class="identifier">read_write</span><span class="special">);</span> |
| |
| <span class="comment">//Get the address of the mapped region |
| </span> <span class="keyword">void</span> <span class="special">*</span> <span class="identifier">addr</span> <span class="special">=</span> <span class="identifier">region</span><span class="special">.</span><span class="identifier">get_address</span><span class="special">();</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span> <span class="special">=</span> <span class="identifier">region</span><span class="special">.</span><span class="identifier">get_size</span><span class="special">();</span> |
| |
| <span class="comment">//Write all the memory to 1 |
| </span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">memset</span><span class="special">(</span><span class="identifier">addr</span><span class="special">,</span> <span class="number">1</span><span class="special">,</span> <span class="identifier">size</span><span class="special">);</span> |
| |
| <span class="comment">//Launch child process |
| </span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">s</span><span class="special">(</span><span class="identifier">argv</span><span class="special">[</span><span class="number">0</span><span class="special">]);</span> <span class="identifier">s</span> <span class="special">+=</span> <span class="string">" child "</span><span class="special">;</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="number">0</span> <span class="special">!=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">system</span><span class="special">(</span><span class="identifier">s</span><span class="special">.</span><span class="identifier">c_str</span><span class="special">()))</span> |
| <span class="keyword">return</span> <span class="number">1</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="keyword">else</span><span class="special">{</span> <span class="comment">//Child process executes this |
| </span> <span class="special">{</span> <span class="comment">//Open the file mapping and map it as read-only |
| </span> <span class="identifier">file_mapping</span> <span class="identifier">m_file</span><span class="special">(</span><span class="string">"file.bin"</span><span class="special">,</span> <span class="identifier">read_only</span><span class="special">);</span> |
| |
| <span class="identifier">mapped_region</span> <span class="identifier">region</span><span class="special">(</span><span class="identifier">m_file</span><span class="special">,</span> <span class="identifier">read_only</span><span class="special">);</span> |
| |
| <span class="comment">//Get the address of the mapped region |
| </span> <span class="keyword">void</span> <span class="special">*</span> <span class="identifier">addr</span> <span class="special">=</span> <span class="identifier">region</span><span class="special">.</span><span class="identifier">get_address</span><span class="special">();</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span> <span class="special">=</span> <span class="identifier">region</span><span class="special">.</span><span class="identifier">get_size</span><span class="special">();</span> |
| |
| <span class="comment">//Check that memory was initialized to 1 |
| </span> <span class="keyword">const</span> <span class="keyword">char</span> <span class="special">*</span><span class="identifier">mem</span> <span class="special">=</span> <span class="keyword">static_cast</span><span class="special"><</span><span class="keyword">char</span><span class="special">*>(</span><span class="identifier">addr</span><span class="special">);</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special"><</span> <span class="identifier">size</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="keyword">if</span><span class="special">(*</span><span class="identifier">mem</span><span class="special">++</span> <span class="special">!=</span> <span class="number">1</span><span class="special">)</span> |
| <span class="keyword">return</span> <span class="number">1</span><span class="special">;</span> <span class="comment">//Error checking memory |
| </span> <span class="special">}</span> |
| <span class="special">{</span> <span class="comment">//Now test it reading the file |
| </span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">filebuf</span> <span class="identifier">fbuf</span><span class="special">;</span> |
| <span class="identifier">fbuf</span><span class="special">.</span><span class="identifier">open</span><span class="special">(</span><span class="string">"file.bin"</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ios_base</span><span class="special">::</span><span class="identifier">in</span> <span class="special">|</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ios_base</span><span class="special">::</span><span class="identifier">binary</span><span class="special">);</span> |
| |
| <span class="comment">//Read it to memory |
| </span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">char</span><span class="special">></span> <span class="identifier">vect</span><span class="special">(</span><span class="identifier">FileSize</span><span class="special">,</span> <span class="number">0</span><span class="special">);</span> |
| <span class="identifier">fbuf</span><span class="special">.</span><span class="identifier">sgetn</span><span class="special">(&</span><span class="identifier">vect</span><span class="special">[</span><span class="number">0</span><span class="special">],</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">streamsize</span><span class="special">(</span><span class="identifier">vect</span><span class="special">.</span><span class="identifier">size</span><span class="special">()));</span> |
| |
| <span class="comment">//Check that memory was initialized to 1 |
| </span> <span class="keyword">const</span> <span class="keyword">char</span> <span class="special">*</span><span class="identifier">mem</span> <span class="special">=</span> <span class="keyword">static_cast</span><span class="special"><</span><span class="keyword">char</span><span class="special">*>(&</span><span class="identifier">vect</span><span class="special">[</span><span class="number">0</span><span class="special">]);</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special"><</span> <span class="identifier">FileSize</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="keyword">if</span><span class="special">(*</span><span class="identifier">mem</span><span class="special">++</span> <span class="special">!=</span> <span class="number">1</span><span class="special">)</span> |
| <span class="keyword">return</span> <span class="number">1</span><span class="special">;</span> <span class="comment">//Error checking memory |
| </span> <span class="special">}</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_region"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region" title="More About Mapped Regions">More About Mapped Regions</a> |
| </h3></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_one_class">One Class To Rule Them All</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_address_mapping">Mapping Address In Several Processes</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_fixed_address_mapping">Fixed Address Mapping</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_mapping_problems">Mapping Offset And Address Limitations</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_one_class"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_one_class" title="One Class To Rule Them All">One Class To Rule Them All</a> |
| </h4></div></div></div> |
| <p> |
| As we have seen, both <code class="computeroutput"><span class="identifier">shared_memory_object</span></code> and <code class="computeroutput"><span class="identifier">file_mapping</span></code> objects can be used |
| to create <code class="computeroutput"><span class="identifier">mapped_region</span></code> objects. A mapped region created from a shared memory |
| object or a file mapping are the same class and this has many advantages. |
| </p> |
| <p> |
| One can, for example, mix in STL containers mapped regions from shared memory |
| and memory mapped files. The libraries that only depend on mapped regions can |
| be used to work with shared memory or memory mapped files without recompiling them. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_address_mapping"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_address_mapping" title="Mapping Address In Several Processes">Mapping Address In Several Processes</a> |
| </h4></div></div></div> |
| <p> |
| In the example we have seen, the file or shared memory contents are mapped |
| to the address space of the process, but the address was chosen by the operating |
| system. |
| </p> |
| <p> |
| If several processes map the same file/shared memory, the mapping address will be |
| surely different in each process. Since each process might have used its address space |
| in a different way (allocation of more or less dynamic memory, for example), there is |
| no guarantee that the file/shared memory is going to be mapped in the same address. |
| </p> |
| <p> |
| If two processes map the same object in different addresses, this invalids the use |
| of pointers in that memory, since the pointer (which is an absolute address) would |
| only make sense for the process that wrote it. The solution for this is to use offsets |
| (distance) between objects instead of pointers: If two objects are placed in the same |
| shared memory segment by one process, <span class="bold"><strong>the address of each object will be different</strong></span> |
| in another process but <span class="bold"><strong>the distance between them (in bytes) will be the same</strong></span>. |
| </p> |
| <p> |
| So the first advice when mapping shared memory and memory mapped files is to avoid |
| using raw pointers, unless you know what you are doing. Use offsets between data or |
| relative pointers to obtain pointer functionality when an object placed in a mapped |
| region wants to point to an object placed in the same mapped region. <span class="bold"><strong>Boost.Interprocess</strong></span> |
| offers a smart pointer called <code class="computeroutput"><a class="link" href="../boost/interprocess/offset_ptr.html" title="Class template offset_ptr">boost::interprocess::offset_ptr</a></code> that |
| can be safely placed in shared memory and that can be used to point to another |
| object placed in the same shared memory / memory mapped file. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_fixed_address_mapping"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_fixed_address_mapping" title="Fixed Address Mapping">Fixed Address Mapping</a> |
| </h4></div></div></div> |
| <p> |
| The use of relative pointers is less efficient than using raw pointers, so if a user |
| can succeed mapping the same file or shared memory object in the same address in two |
| processes, using raw pointers can be a good idea. |
| </p> |
| <p> |
| To map an object in a fixed address, the user can specify that address in the |
| <code class="computeroutput"><span class="identifier">mapped</span> <span class="identifier">region</span></code>'s constructor: |
| </p> |
| <pre class="programlisting"><span class="identifier">mapped_region</span> <span class="identifier">region</span> <span class="special">(</span> <span class="identifier">shm</span> <span class="comment">//Map shared memory |
| </span> <span class="special">,</span> <span class="identifier">read_write</span> <span class="comment">//Map it as read-write |
| </span> <span class="special">,</span> <span class="number">0</span> <span class="comment">//Map from offset 0 |
| </span> <span class="special">,</span> <span class="number">0</span> <span class="comment">//Map until the end |
| </span> <span class="special">,</span> <span class="special">(</span><span class="keyword">void</span><span class="special">*)</span><span class="number">0x3F000000</span> <span class="comment">//Map it exactly there |
| </span> <span class="special">);</span> |
| </pre> |
| <p> |
| However, the user can't map the region in any address, even if the address is not |
| being used. The offset parameter that marks the start of the mapping region |
| is also limited. These limitations are explained in the next section. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_mapping_problems"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_mapping_problems" title="Mapping Offset And Address Limitations">Mapping Offset And Address Limitations</a> |
| </h4></div></div></div> |
| <p> |
| As mentioned, the user can't map the memory mappable object at any address and it can |
| specify the offset of the mappable object that is equivalent to the start of the mapping |
| region to an arbitrary value. |
| Most operating systems limit the mapping address and the offset of the mappable object |
| to a multiple of a value called <span class="bold"><strong>page size</strong></span>. This is due to the fact that the |
| <span class="bold"><strong>operating system performs mapping operations over whole pages</strong></span>. |
| </p> |
| <p> |
| If fixed mapping address is used, <span class="emphasis"><em>offset</em></span> and <span class="emphasis"><em>address</em></span> |
| parameters should be multiples of that value. |
| This value is, typically, 4KB or 8KB for 32 bit operating systems. |
| </p> |
| <pre class="programlisting"><span class="comment">//These might fail because the offset is not a multiple of the page size |
| </span><span class="comment">//and we are using fixed address mapping |
| </span><span class="identifier">mapped_region</span> <span class="identifier">region1</span><span class="special">(</span> <span class="identifier">shm</span> <span class="comment">//Map shared memory |
| </span> <span class="special">,</span> <span class="identifier">read_write</span> <span class="comment">//Map it as read-write |
| </span> <span class="special">,</span> <span class="number">1</span> <span class="comment">//Map from offset 1 |
| </span> <span class="special">,</span> <span class="number">1</span> <span class="comment">//Map 1 byte |
| </span> <span class="special">,</span> <span class="special">(</span><span class="keyword">void</span><span class="special">*)</span><span class="number">0x3F000000</span> <span class="comment">//Aligned mapping address |
| </span> <span class="special">);</span> |
| |
| <span class="comment">//These might fail because the address is not a multiple of the page size |
| </span><span class="identifier">mapped_region</span> <span class="identifier">region2</span><span class="special">(</span> <span class="identifier">shm</span> <span class="comment">//Map shared memory |
| </span> <span class="special">,</span> <span class="identifier">read_write</span> <span class="comment">//Map it as read-write |
| </span> <span class="special">,</span> <span class="number">0</span> <span class="comment">//Map from offset 0 |
| </span> <span class="special">,</span> <span class="number">1</span> <span class="comment">//Map 1 byte |
| </span> <span class="special">,</span> <span class="special">(</span><span class="keyword">void</span><span class="special">*)</span><span class="number">0x3F000001</span> <span class="comment">//Not aligned mapping address |
| </span> <span class="special">);</span> |
| </pre> |
| <p> |
| Since the operating system performs mapping operations over whole pages, specifying |
| a mapping <span class="emphasis"><em>size</em></span> or <span class="emphasis"><em>offset</em></span> that are not multiple of the page size will waste |
| more resources than necessary. If the user specifies the following 1 byte mapping: |
| </p> |
| <pre class="programlisting"><span class="comment">//Map one byte of the shared memory object. |
| </span><span class="comment">//A whole memory page will be used for this. |
| </span><span class="identifier">mapped_region</span> <span class="identifier">region</span> <span class="special">(</span> <span class="identifier">shm</span> <span class="comment">//Map shared memory |
| </span> <span class="special">,</span> <span class="identifier">read_write</span> <span class="comment">//Map it as read-write |
| </span> <span class="special">,</span> <span class="number">0</span> <span class="comment">//Map from offset 0 |
| </span> <span class="special">,</span> <span class="number">1</span> <span class="comment">//Map 1 byte |
| </span> <span class="special">);</span> |
| </pre> |
| <p> |
| The operating system will reserve a whole page that will not be reused by any |
| other mapping so we are going to waste <span class="bold"><strong>(page size - 1)</strong></span> bytes. If we want |
| to use efficiently operating system resources, we should create regions whose size |
| is a multiple of <span class="bold"><strong>page size</strong></span> bytes. If the user specifies the following two |
| mapped regions for a file with which has <code class="computeroutput"><span class="number">2</span><span class="special">*</span><span class="identifier">page_size</span></code> bytes: |
| </p> |
| <pre class="programlisting"><span class="comment">//Map the first quarter of the file |
| </span><span class="comment">//This will use a whole page |
| </span><span class="identifier">mapped_region</span> <span class="identifier">region1</span><span class="special">(</span> <span class="identifier">shm</span> <span class="comment">//Map shared memory |
| </span> <span class="special">,</span> <span class="identifier">read_write</span> <span class="comment">//Map it as read-write |
| </span> <span class="special">,</span> <span class="number">0</span> <span class="comment">//Map from offset 0 |
| </span> <span class="special">,</span> <span class="identifier">page_size</span><span class="special">/</span><span class="number">2</span> <span class="comment">//Map page_size/2 bytes |
| </span> <span class="special">);</span> |
| |
| <span class="comment">//Map the rest of the file |
| </span><span class="comment">//This will use a 2 pages |
| </span><span class="identifier">mapped_region</span> <span class="identifier">region2</span><span class="special">(</span> <span class="identifier">shm</span> <span class="comment">//Map shared memory |
| </span> <span class="special">,</span> <span class="identifier">read_write</span> <span class="comment">//Map it as read-write |
| </span> <span class="special">,</span> <span class="identifier">page_size</span><span class="special">/</span><span class="number">2</span> <span class="comment">//Map from offset 0 |
| </span> <span class="special">,</span> <span class="number">3</span><span class="special">*</span><span class="identifier">page_size</span><span class="special">/</span><span class="number">2</span> <span class="comment">//Map the rest of the shared memory |
| </span> <span class="special">);</span> |
| </pre> |
| <p> |
| In this example, a half of the page is wasted in the first mapping and another |
| half is wasted in the second because the offset is not a multiple of the |
| page size. The mapping with the minimum resource usage would be to map whole pages: |
| </p> |
| <pre class="programlisting"><span class="comment">//Map the whole first half: uses 1 page |
| </span><span class="identifier">mapped_region</span> <span class="identifier">region1</span><span class="special">(</span> <span class="identifier">shm</span> <span class="comment">//Map shared memory |
| </span> <span class="special">,</span> <span class="identifier">read_write</span> <span class="comment">//Map it as read-write |
| </span> <span class="special">,</span> <span class="number">0</span> <span class="comment">//Map from offset 0 |
| </span> <span class="special">,</span> <span class="identifier">page_size</span> <span class="comment">//Map a full page_size |
| </span> <span class="special">);</span> |
| |
| <span class="comment">//Map the second half: uses 1 page |
| </span><span class="identifier">mapped_region</span> <span class="identifier">region2</span><span class="special">(</span> <span class="identifier">shm</span> <span class="comment">//Map shared memory |
| </span> <span class="special">,</span> <span class="identifier">read_write</span> <span class="comment">//Map it as read-write |
| </span> <span class="special">,</span> <span class="identifier">page_size</span> <span class="comment">//Map from offset 0 |
| </span> <span class="special">,</span> <span class="identifier">page_size</span> <span class="comment">//Map the rest |
| </span> <span class="special">);</span> |
| </pre> |
| <p> |
| How can we obtain the <span class="bold"><strong>page size</strong></span>? The <code class="computeroutput"><span class="identifier">mapped_region</span></code> class has a static |
| function that returns that value: |
| </p> |
| <pre class="programlisting"><span class="comment">//Obtain the page size of the system |
| </span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">page_size</span> <span class="special">=</span> <span class="identifier">mapped_region</span><span class="special">::</span><span class="identifier">get_page_size</span><span class="special">();</span> |
| </pre> |
| <p> |
| The operating system might also limit the number of mapped memory regions per |
| process or per system. |
| </p> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations" title="Limitations When Constructing Objects In Mapped Regions">Limitations When Constructing Objects In Mapped Regions</a> |
| </h3></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations.offset_pointer">Offset pointers instead of raw pointers</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations.references_forbidden">References forbidden</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations.virtuality_limitation">Virtuality forbidden</a></span></dt> |
| <dt><span class="section"><a href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations.statics_warning">Be careful with static class members</a></span></dt> |
| </dl></div> |
| <p> |
| When two processes create a mapped region of the same mappable object, two processes |
| can communicate writing and reading that memory. A process could construct a C++ object |
| in that memory so that the second process can use it. However, a mapped region shared |
| by multiple processes, can't hold any C++ object, because not every class is ready |
| to be a process-shared object, specially, if the mapped region is mapped in different |
| address in each process. |
| </p> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations.offset_pointer"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations.offset_pointer" title="Offset pointers instead of raw pointers">Offset pointers instead of raw pointers</a> |
| </h4></div></div></div> |
| <p> |
| When placing objects in a mapped region and mapping |
| that region in different address in every process, |
| raw pointers are a problem since they are only valid for the |
| process that placed them there. To solve this, <span class="bold"><strong>Boost.Interprocess</strong></span> offers |
| a special smart pointer that can be used instead of a raw pointer. |
| So user classes containing raw pointers (or Boost smart pointers, that |
| internally own a raw pointer) can't be safely placed in a process shared |
| mapped region. These pointers must be replaced with offset pointers, and |
| these pointers must point only to objects placed in the same mapped region |
| if you want to use these shared objects from different processes. |
| </p> |
| <p> |
| Of course, a pointer placed in a mapped region shared between processes should |
| only point to an object of that mapped region. Otherwise, the pointer would |
| point to an address that it's only valid one process and other |
| processes may crash when accessing to that address. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations.references_forbidden"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations.references_forbidden" title="References forbidden">References forbidden</a> |
| </h4></div></div></div> |
| <p> |
| References suffer from the same problem as pointers |
| (mainly because they are implemented as pointers). |
| However, it is not possible to create a fully workable |
| smart reference currently in C++ (for example, |
| <code class="computeroutput"><span class="keyword">operator</span> <span class="special">.()</span></code> can't be overloaded). Because of this, |
| if the user wants to put an object in shared memory, |
| the object can't have any (smart or not) reference |
| as a member. |
| </p> |
| <p> |
| References will only work if the mapped region is mapped in the same |
| base address in all processes sharing a memory segment. |
| Like pointers, a reference placed in a mapped region should only point |
| to an object of that mapped region. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations.virtuality_limitation"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations.virtuality_limitation" title="Virtuality forbidden">Virtuality forbidden</a> |
| </h4></div></div></div> |
| <p> |
| The virtual table pointer and the virtual table |
| are in the address space of the process |
| that constructs the object, so if we place a class |
| with a virtual function or virtual base class, the virtual |
| pointer placed in shared memory will be invalid for other processes |
| and they will crash. |
| </p> |
| <p> |
| This problem is very difficult to solve, since each process needs a |
| different virtual table pointer and the object that contains that pointer |
| is shared across many processes. Even if we map the mapped region in |
| the same address in every process, the virtual table can be in a different |
| address in every process. To enable virtual functions for objects |
| shared between processes, deep compiler changes are needed and virtual |
| functions would suffer a performance hit. That's why |
| <span class="bold"><strong>Boost.Interprocess</strong></span> does not have any plan to support virtual function |
| and virtual inheritance in mapped regions shared between processes. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations.statics_warning"></a><a class="link" href="sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations.statics_warning" title="Be careful with static class members">Be careful with static class members</a> |
| </h4></div></div></div> |
| <p> |
| Static members of classes are global objects shared by |
| all instances of the class. Because of this, static |
| members are implemented as global variables in processes. |
| </p> |
| <p> |
| When constructing a class with static members, each process |
| has its own copy of the static member, so updating a static |
| member in one process does not change the value of the static |
| member the another process. So be careful with these classes. Static |
| members are not dangerous if they are just constant variables initialized |
| when the process starts, but they don't change at all (for example, |
| when used like enums) and their value is the same for all processes. |
| </p> |
| </div> |
| </div> |
| </div> |
| <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> |
| <td align="left"></td> |
| <td align="right"><div class="copyright-footer">Copyright © 2005 - 2010 Ion Gaztanaga<p> |
| Distributed under the Boost Software License, Version 1.0. (See accompanying |
| file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>) |
| </p> |
| </div></td> |
| </tr></table> |
| <hr> |
| <div class="spirit-nav"> |
| <a accesskey="p" href="some_basic_explanations.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../interprocess.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="offset_ptr.html"><img src="../../../doc/src/images/next.png" alt="Next"></a> |
| </div> |
| </body> |
| </html> |