| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> |
| <title>Synchronization mechanisms</title> |
| <link rel="stylesheet" href="../../../doc/src/boostbook.css" type="text/css"> |
| <meta name="generator" content="DocBook XSL Stylesheets V1.78.1"> |
| <link rel="home" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset"> |
| <link rel="up" href="../interprocess.html" title="Chapter 14. Boost.Interprocess"> |
| <link rel="prev" href="offset_ptr.html" title="Mapping Address Independent Pointer: offset_ptr"> |
| <link rel="next" href="managed_memory_segments.html" title="Managed Memory Segments"> |
| </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="offset_ptr.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="managed_memory_segments.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.synchronization_mechanisms"></a><a class="link" href="synchronization_mechanisms.html" title="Synchronization mechanisms">Synchronization |
| mechanisms</a> |
| </h2></div></div></div> |
| <div class="toc"><dl class="toc"> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.synchronization_mechanisms_overview">Synchronization |
| mechanisms overview</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes">Mutexes</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.conditions">Conditions</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.semaphores">Semaphores</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes">Sharable |
| and Upgradable Mutexes</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions">Lock |
| Transfers Through Move Semantics</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock">File |
| Locks</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.message_queue">Message |
| Queue</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="interprocess.synchronization_mechanisms.synchronization_mechanisms_overview"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.synchronization_mechanisms_overview" title="Synchronization mechanisms overview">Synchronization |
| mechanisms overview</a> |
| </h3></div></div></div> |
| <div class="toc"><dl class="toc"> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.synchronization_mechanisms_overview.synchronization_mechanisms_named_vs_anonymous">Named |
| And Anonymous Synchronization Mechanisms</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.synchronization_mechanisms_overview.synchronization_mechanisms_types">Types |
| Of Synchronization Mechanisms</a></span></dt> |
| </dl></div> |
| <p> |
| As mentioned before, the ability to shared memory between processes through |
| memory mapped files or shared memory objects is not very useful if the access |
| to that memory can't be effectively synchronized. This is the same problem |
| that happens with thread-synchronization mechanisms, where heap memory and |
| global variables are shared between threads, but the access to these resources |
| needs to be synchronized typically through mutex and condition variables. |
| <span class="bold"><strong>Boost.Threads</strong></span> implements these synchronization |
| utilities between threads inside the same process. <span class="bold"><strong>Boost.Interprocess</strong></span> |
| implements similar mechanisms to synchronize threads from different processes. |
| </p> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.synchronization_mechanisms_overview.synchronization_mechanisms_named_vs_anonymous"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.synchronization_mechanisms_overview.synchronization_mechanisms_named_vs_anonymous" title="Named And Anonymous Synchronization Mechanisms">Named |
| And Anonymous Synchronization Mechanisms</a> |
| </h4></div></div></div> |
| <p> |
| <span class="bold"><strong>Boost.Interprocess</strong></span> presents two types |
| of synchronization objects: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| <span class="bold"><strong>Named utilities</strong></span>: When two processes |
| want to create an object of such type, both processes must <span class="emphasis"><em>create</em></span> |
| or <span class="emphasis"><em>open</em></span> an object using the same name. This is |
| similar to creating or opening files: a process creates a file with |
| using a <code class="computeroutput"><span class="identifier">fstream</span></code> with |
| the name <span class="emphasis"><em>filename</em></span> and another process opens that |
| file using another <code class="computeroutput"><span class="identifier">fstream</span></code> |
| with the same <span class="emphasis"><em>filename</em></span> argument. <span class="bold"><strong>Each |
| process uses a different object to access to the resource, but both |
| processes are using the same underlying resource</strong></span>. |
| </li> |
| <li class="listitem"> |
| <span class="bold"><strong>Anonymous utilities</strong></span>: Since these utilities |
| have no name, two processes must share <span class="bold"><strong>the same |
| object</strong></span> through shared memory or memory mapped files. This |
| is similar to traditional thread synchronization objects: <span class="bold"><strong>Both processes share the same object</strong></span>. Unlike |
| thread synchronization, where global variables and heap memory is shared |
| between threads of the same process, sharing objects between two threads |
| from different process can be only possible through mapped regions |
| that map the same mappable resource (for example, shared memory or |
| memory mapped files). |
| </li> |
| </ul></div> |
| <p> |
| Each type has it's own advantages and disadvantages: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| Named utilities are easier to handle for simple synchronization tasks, |
| since both process don't have to create a shared memory region and |
| construct the synchronization mechanism there. |
| </li> |
| <li class="listitem"> |
| Anonymous utilities can be serialized to disk when using memory mapped |
| objects obtaining automatic persistence of synchronization utilities. |
| One could construct a synchronization utility in a memory mapped file, |
| reboot the system, map the file again, and use the synchronization |
| utility again without any problem. This can't be achieved with named |
| synchronization utilities. |
| </li> |
| </ul></div> |
| <p> |
| The main interface difference between named and anonymous utilities are |
| the constructors. Usually anonymous utilities have only one constructor, |
| whereas the named utilities have several constructors whose first argument |
| is a special type that requests creation, opening or opening or creation |
| of the underlying resource: |
| </p> |
| <pre class="programlisting"><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="comment">//Create the synchronization utility. If it previously</span> |
| <span class="comment">//exists, throws an error</span> |
| <span class="identifier">NamedUtility</span><span class="special">(</span><span class="identifier">create_only</span><span class="special">,</span> <span class="special">...)</span> |
| |
| <span class="comment">//Open the synchronization utility. If it does not previously</span> |
| <span class="comment">//exist, it's created.</span> |
| <span class="identifier">NamedUtility</span><span class="special">(</span><span class="identifier">open_or_create</span><span class="special">,</span> <span class="special">...)</span> |
| |
| <span class="comment">//Open the synchronization utility. If it does not previously</span> |
| <span class="comment">//exist, throws an error.</span> |
| <span class="identifier">NamedUtility</span><span class="special">(</span><span class="identifier">open_only</span><span class="special">,</span> <span class="special">...)</span> |
| </pre> |
| <p> |
| On the other hand the anonymous synchronization utility can only be created |
| and the processes must synchronize using other mechanisms who creates the |
| utility: |
| </p> |
| <pre class="programlisting"><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="comment">//Create the synchronization utility.</span> |
| <span class="identifier">AnonymousUtility</span><span class="special">(...)</span> |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.synchronization_mechanisms_overview.synchronization_mechanisms_types"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.synchronization_mechanisms_overview.synchronization_mechanisms_types" title="Types Of Synchronization Mechanisms">Types |
| Of Synchronization Mechanisms</a> |
| </h4></div></div></div> |
| <p> |
| Apart from its named/anonymous nature, <span class="bold"><strong>Boost.Interprocess</strong></span> |
| presents the following synchronization utilities: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| Mutexes (named and anonymous) |
| </li> |
| <li class="listitem"> |
| Condition variables (named and anonymous) |
| </li> |
| <li class="listitem"> |
| Semaphores (named and anonymous) |
| </li> |
| <li class="listitem"> |
| Upgradable mutexes |
| </li> |
| <li class="listitem"> |
| File locks |
| </li> |
| </ul></div> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="interprocess.synchronization_mechanisms.mutexes"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes" title="Mutexes">Mutexes</a> |
| </h3></div></div></div> |
| <div class="toc"><dl class="toc"> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes.mutexes_whats_a_mutex">What's |
| A Mutex?</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes.mutexes_mutex_operations">Mutex |
| Operations</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes.mutexes_interprocess_mutexes">Boost.Interprocess |
| Mutex Types And Headers</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes.mutexes_scoped_lock">Scoped |
| lock</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes.mutexes_anonymous_example">Anonymous |
| mutex example</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes.mutexes_named_example">Named |
| mutex example</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.mutexes.mutexes_whats_a_mutex"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes.mutexes_whats_a_mutex" title="What's A Mutex?">What's |
| A Mutex?</a> |
| </h4></div></div></div> |
| <p> |
| <span class="emphasis"><em>Mutex</em></span> stands for <span class="bold"><strong>mut</strong></span>ual |
| <span class="bold"><strong>ex</strong></span>clusion and it's the most basic form |
| of synchronization between processes. Mutexes guarantee that only one thread |
| can lock a given mutex. If a code section is surrounded by a mutex locking |
| and unlocking, it's guaranteed that only a thread at a time executes that |
| section of code. When that thread <span class="bold"><strong>unlocks</strong></span> |
| the mutex, other threads can enter to that code region: |
| </p> |
| <pre class="programlisting"><span class="comment">//The mutex has been previously constructed</span> |
| |
| <span class="identifier">lock_the_mutex</span><span class="special">();</span> |
| |
| <span class="comment">//This code will be executed only by one thread</span> |
| <span class="comment">//at a time.</span> |
| |
| <span class="identifier">unlock_the_mutex</span><span class="special">();</span> |
| </pre> |
| <p> |
| A mutex can also be <span class="bold"><strong>recursive</strong></span> or <span class="bold"><strong>non-recursive</strong></span>: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| Recursive mutexes can be locked several times by the same thread. To |
| fully unlock the mutex, the thread has to unlock the mutex the same |
| times it has locked it. |
| </li> |
| <li class="listitem"> |
| Non-recursive mutexes can't be locked several times by the same thread. |
| If a mutex is locked twice by a thread, the result is undefined, it |
| might throw an error or the thread could be blocked forever. |
| </li> |
| </ul></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.mutexes.mutexes_mutex_operations"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes.mutexes_mutex_operations" title="Mutex Operations">Mutex |
| Operations</a> |
| </h4></div></div></div> |
| <p> |
| All the mutex types from <span class="bold"><strong>Boost.Interprocess</strong></span> |
| implement the following operations: |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void lock()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to obtain |
| ownership of the mutex, and if another thread has ownership of the mutex, |
| it waits until it can obtain the ownership. If a thread takes ownership |
| of the mutex the mutex must be unlocked by the same thread. If the mutex |
| supports recursive locking, the mutex must be unlocked the same number |
| of times it is locked. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool try_lock()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to obtain |
| ownership of the mutex, and if another thread has ownership of the mutex |
| returns immediately. If the mutex supports recursive locking, the mutex |
| must be unlocked the same number of times it is locked. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If the thread acquires ownership |
| of the mutex, returns true, if the another thread has ownership of the |
| mutex, returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool timed_lock(const boost::posix_time::ptime |
| &abs_time)</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread will try to |
| obtain exclusive ownership of the mutex if it can do so in until the specified |
| time is reached. If the mutex supports recursive locking, the mutex must |
| be unlocked the same number of times it is locked. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If the thread acquires ownership |
| of the mutex, returns true, if the timeout expires returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void unlock()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have exclusive |
| ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread releases the |
| exclusive ownership of the mutex. If the mutex supports recursive locking, |
| the mutex must be unlocked the same number of times it is locked. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| <div class="important"><table border="0" summary="Important"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../doc/src/images/important.png"></td> |
| <th align="left">Important</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">ptime</span></code> absolute time points used by |
| Boost.Interprocess synchronization mechanisms are UTC time points, not |
| local time points |
| </p></td></tr> |
| </table></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.mutexes.mutexes_interprocess_mutexes"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes.mutexes_interprocess_mutexes" title="Boost.Interprocess Mutex Types And Headers">Boost.Interprocess |
| Mutex Types And Headers</a> |
| </h4></div></div></div> |
| <p> |
| Boost.Interprocess offers the following mutex types: |
| </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">sync</span><span class="special">/</span><span class="identifier">interprocess_mutex</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/interprocess_mutex.html" title="Class interprocess_mutex">interprocess_mutex</a></code>: |
| A non-recursive, anonymous mutex that can be placed in shared memory |
| or memory mapped files. |
| </li></ul></div> |
| <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">sync</span><span class="special">/</span><span class="identifier">interprocess_recursive_mutex</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/interprocess_r_idp56590896.html" title="Class interprocess_recursive_mutex">interprocess_recursive_mutex</a></code>: |
| A recursive, anonymous mutex that can be placed in shared memory or |
| memory mapped files. |
| </li></ul></div> |
| <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">sync</span><span class="special">/</span><span class="identifier">named_mutex</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/named_mutex.html" title="Class named_mutex">named_mutex</a></code>: |
| A non-recursive, named mutex. |
| </li></ul></div> |
| <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">sync</span><span class="special">/</span><span class="identifier">named_recursive_mutex</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/named_recursive_mutex.html" title="Class named_recursive_mutex">named_recursive_mutex</a></code>: |
| A recursive, named mutex. |
| </li></ul></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.mutexes.mutexes_scoped_lock"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes.mutexes_scoped_lock" title="Scoped lock">Scoped |
| lock</a> |
| </h4></div></div></div> |
| <p> |
| It's very important to unlock a mutex after the process has read or written |
| the data. This can be difficult when dealing with exceptions, so usually |
| mutexes are used with a scoped lock, a class that can guarantee that a |
| mutex will always be unlocked even when an exception occurs. To use a scoped |
| lock just include: |
| </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">sync</span><span class="special">/</span><span class="identifier">scoped_lock</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <p> |
| Basically, a scoped lock calls <span class="bold"><strong>unlock()</strong></span> |
| in its destructor, and a mutex is always unlocked when an exception occurs. |
| Scoped lock has many constructors to lock, try_lock, timed_lock a mutex |
| or not to lock it at all. |
| </p> |
| <pre class="programlisting"><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="comment">//Let's create any mutex type:</span> |
| <span class="identifier">MutexType</span> <span class="identifier">mutex</span><span class="special">;</span> |
| |
| <span class="special">{</span> |
| <span class="comment">//This will lock the mutex</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">MutexType</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">mutex</span><span class="special">);</span> |
| |
| <span class="comment">//Some code</span> |
| |
| <span class="comment">//The mutex will be unlocked here</span> |
| <span class="special">}</span> |
| |
| <span class="special">{</span> |
| <span class="comment">//This will try_lock the mutex</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">MutexType</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">mutex</span><span class="special">,</span> <span class="identifier">try_to_lock</span><span class="special">);</span> |
| |
| <span class="comment">//Check if the mutex has been successfully locked</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">lock</span><span class="special">){</span> |
| <span class="comment">//Some code</span> |
| <span class="special">}</span> |
| |
| <span class="comment">//If the mutex was locked it will be unlocked</span> |
| <span class="special">}</span> |
| |
| <span class="special">{</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">ptime</span> <span class="identifier">abs_time</span> <span class="special">=</span> <span class="special">...</span> |
| |
| <span class="comment">//This will timed_lock the mutex</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">MutexType</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">mutex</span><span class="special">,</span> <span class="identifier">abs_time</span><span class="special">);</span> |
| |
| <span class="comment">//Check if the mutex has been successfully locked</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">lock</span><span class="special">){</span> |
| <span class="comment">//Some code</span> |
| <span class="special">}</span> |
| |
| <span class="comment">//If the mutex was locked it will be unlocked</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| For more information, check the <code class="computeroutput"><a class="link" href="../boost/interprocess/scoped_lock.html" title="Class template scoped_lock">scoped_lock's |
| reference</a></code>. |
| </p> |
| <div class="important"><table border="0" summary="Important"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../doc/src/images/important.png"></td> |
| <th align="left">Important</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">ptime</span></code> absolute time points used by |
| Boost.Interprocess synchronization mechanisms are UTC time points, not |
| local time points |
| </p></td></tr> |
| </table></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.mutexes.mutexes_anonymous_example"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes.mutexes_anonymous_example" title="Anonymous mutex example">Anonymous |
| mutex example</a> |
| </h4></div></div></div> |
| <p> |
| Imagine that two processes need to write traces to a cyclic buffer built |
| in shared memory. Each process needs to obtain exclusive access to the |
| cyclic buffer, write the trace and continue. |
| </p> |
| <p> |
| To protect the cyclic buffer, we can store a process shared mutex in the |
| cyclic buffer. Each process will lock the mutex before writing the data |
| and will write a flag when ends writing the traces (<code class="computeroutput"><span class="identifier">doc_anonymous_mutex_shared_data</span><span class="special">.</span><span class="identifier">hpp</span></code> |
| header): |
| </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">sync</span><span class="special">/</span><span class="identifier">interprocess_mutex</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| |
| <span class="keyword">struct</span> <span class="identifier">shared_memory_log</span> |
| <span class="special">{</span> |
| <span class="keyword">enum</span> <span class="special">{</span> <span class="identifier">NumItems</span> <span class="special">=</span> <span class="number">100</span> <span class="special">};</span> |
| <span class="keyword">enum</span> <span class="special">{</span> <span class="identifier">LineSize</span> <span class="special">=</span> <span class="number">100</span> <span class="special">};</span> |
| |
| <span class="identifier">shared_memory_log</span><span class="special">()</span> |
| <span class="special">:</span> <span class="identifier">current_line</span><span class="special">(</span><span class="number">0</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">end_a</span><span class="special">(</span><span class="keyword">false</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">end_b</span><span class="special">(</span><span class="keyword">false</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">//Mutex to protect access to the queue</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">::</span><span class="identifier">interprocess_mutex</span> <span class="identifier">mutex</span><span class="special">;</span> |
| |
| <span class="comment">//Items to fill</span> |
| <span class="keyword">char</span> <span class="identifier">items</span><span class="special">[</span><span class="identifier">NumItems</span><span class="special">][</span><span class="identifier">LineSize</span><span class="special">];</span> |
| <span class="keyword">int</span> <span class="identifier">current_line</span><span class="special">;</span> |
| <span class="keyword">bool</span> <span class="identifier">end_a</span><span class="special">;</span> |
| <span class="keyword">bool</span> <span class="identifier">end_b</span><span class="special">;</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| This is the process main process. Creates the shared memory, constructs |
| the cyclic buffer and start writing traces: |
| </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">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">sync</span><span class="special">/</span><span class="identifier">scoped_lock</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="string">"doc_anonymous_mutex_shared_data.hpp"</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">cstdio</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">int</span> <span class="identifier">main</span> <span class="special">()</span> |
| <span class="special">{</span> |
| <span class="keyword">try</span><span class="special">{</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="comment">//only create</span> |
| <span class="special">,</span><span class="string">"MySharedMemory"</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> |
| |
| <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="keyword">sizeof</span><span class="special">(</span><span class="identifier">shared_memory_log</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="comment">//What to map</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="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="comment">//Construct the shared structure in memory</span> |
| <span class="identifier">shared_memory_log</span> <span class="special">*</span> <span class="identifier">data</span> <span class="special">=</span> <span class="keyword">new</span> <span class="special">(</span><span class="identifier">addr</span><span class="special">)</span> <span class="identifier">shared_memory_log</span><span class="special">;</span> |
| |
| <span class="comment">//Write some logs</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="keyword">int</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">shared_memory_log</span><span class="special">::</span><span class="identifier">NumItems</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">){</span> |
| <span class="comment">//Lock the mutex</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">interprocess_mutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">mutex</span><span class="special">);</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">sprintf</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">items</span><span class="special">[(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">current_line</span><span class="special">++)</span> <span class="special">%</span> <span class="identifier">shared_memory_log</span><span class="special">::</span><span class="identifier">NumItems</span><span class="special">]</span> |
| <span class="special">,</span><span class="string">"%s_%d"</span><span class="special">,</span> <span class="string">"process_a"</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">i</span> <span class="special">==</span> <span class="special">(</span><span class="identifier">shared_memory_log</span><span class="special">::</span><span class="identifier">NumItems</span><span class="special">-</span><span class="number">1</span><span class="special">))</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">end_a</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">;</span> |
| <span class="comment">//Mutex is released here</span> |
| <span class="special">}</span> |
| |
| <span class="comment">//Wait until the other process ends</span> |
| <span class="keyword">while</span><span class="special">(</span><span class="number">1</span><span class="special">){</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">interprocess_mutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">mutex</span><span class="special">);</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">end_b</span><span class="special">)</span> |
| <span class="keyword">break</span><span class="special">;</span> |
| <span class="special">}</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> |
| The second process opens the shared memory, obtains access to the cyclic |
| buffer and starts writing traces: |
| </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">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">sync</span><span class="special">/</span><span class="identifier">scoped_lock</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="string">"doc_anonymous_mutex_shared_data.hpp"</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">cstdio</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">int</span> <span class="identifier">main</span> <span class="special">()</span> |
| <span class="special">{</span> |
| <span class="comment">//Remove shared memory on destruction</span> |
| <span class="keyword">struct</span> <span class="identifier">shm_remove</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">//Open the 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="comment">//only create</span> |
| <span class="special">,</span><span class="string">"MySharedMemory"</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> |
| |
| <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="comment">//What to map</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="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="comment">//Construct the shared structure in memory</span> |
| <span class="identifier">shared_memory_log</span> <span class="special">*</span> <span class="identifier">data</span> <span class="special">=</span> <span class="keyword">static_cast</span><span class="special"><</span><span class="identifier">shared_memory_log</span><span class="special">*>(</span><span class="identifier">addr</span><span class="special">);</span> |
| |
| <span class="comment">//Write some logs</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="keyword">int</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="number">100</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">){</span> |
| <span class="comment">//Lock the mutex</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">interprocess_mutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">mutex</span><span class="special">);</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">sprintf</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">items</span><span class="special">[(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">current_line</span><span class="special">++)</span> <span class="special">%</span> <span class="identifier">shared_memory_log</span><span class="special">::</span><span class="identifier">NumItems</span><span class="special">]</span> |
| <span class="special">,</span><span class="string">"%s_%d"</span><span class="special">,</span> <span class="string">"process_a"</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">i</span> <span class="special">==</span> <span class="special">(</span><span class="identifier">shared_memory_log</span><span class="special">::</span><span class="identifier">NumItems</span><span class="special">-</span><span class="number">1</span><span class="special">))</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">end_b</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">;</span> |
| <span class="comment">//Mutex is released here</span> |
| <span class="special">}</span> |
| |
| <span class="comment">//Wait until the other process ends</span> |
| <span class="keyword">while</span><span class="special">(</span><span class="number">1</span><span class="special">){</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">interprocess_mutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">mutex</span><span class="special">);</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">end_a</span><span class="special">)</span> |
| <span class="keyword">break</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, a mutex is useful to protect data but not to notify an event |
| to another process. For this, we need a condition variable, as we will |
| see in the next section. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.mutexes.mutexes_named_example"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.mutexes.mutexes_named_example" title="Named mutex example">Named |
| mutex example</a> |
| </h4></div></div></div> |
| <p> |
| Now imagine that two processes want to write a trace to a file. First they |
| write their name, and after that they write the message. Since the operating |
| system can interrupt a process in any moment we can mix parts of the messages |
| of both processes, so we need a way to write the whole message to the file |
| atomically. To achieve this, we can use a named mutex so that each process |
| locks the mutex before writing: |
| </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">sync</span><span class="special">/</span><span class="identifier">scoped_lock</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">sync</span><span class="special">/</span><span class="identifier">named_mutex</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">fstream</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">cstdio</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="keyword">struct</span> <span class="identifier">file_remove</span> |
| <span class="special">{</span> |
| <span class="identifier">file_remove</span><span class="special">()</span> <span class="special">{</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove</span><span class="special">(</span><span class="string">"file_name"</span><span class="special">);</span> <span class="special">}</span> |
| <span class="special">~</span><span class="identifier">file_remove</span><span class="special">(){</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove</span><span class="special">(</span><span class="string">"file_name"</span><span class="special">);</span> <span class="special">}</span> |
| <span class="special">}</span> <span class="identifier">file_remover</span><span class="special">;</span> |
| <span class="keyword">struct</span> <span class="identifier">mutex_remove</span> |
| <span class="special">{</span> |
| <span class="identifier">mutex_remove</span><span class="special">()</span> <span class="special">{</span> <span class="identifier">named_mutex</span><span class="special">::</span><span class="identifier">remove</span><span class="special">(</span><span class="string">"fstream_named_mutex"</span><span class="special">);</span> <span class="special">}</span> |
| <span class="special">~</span><span class="identifier">mutex_remove</span><span class="special">(){</span> <span class="identifier">named_mutex</span><span class="special">::</span><span class="identifier">remove</span><span class="special">(</span><span class="string">"fstream_named_mutex"</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">//Open or create the named mutex</span> |
| <span class="identifier">named_mutex</span> <span class="identifier">mutex</span><span class="special">(</span><span class="identifier">open_or_create</span><span class="special">,</span> <span class="string">"fstream_named_mutex"</span><span class="special">);</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">ofstream</span> <span class="identifier">file</span><span class="special">(</span><span class="string">"file_name"</span><span class="special">);</span> |
| |
| <span class="keyword">for</span><span class="special">(</span><span class="keyword">int</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="number">10</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">){</span> |
| |
| <span class="comment">//Do some operations...</span> |
| |
| <span class="comment">//Write to file atomically</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">named_mutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">mutex</span><span class="special">);</span> |
| <span class="identifier">file</span> <span class="special"><<</span> <span class="string">"Process name, "</span><span class="special">;</span> |
| <span class="identifier">file</span> <span class="special"><<</span> <span class="string">"This is iteration #"</span> <span class="special"><<</span> <span class="identifier">i</span><span class="special">;</span> |
| <span class="identifier">file</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="special">}</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> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="interprocess.synchronization_mechanisms.conditions"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.conditions" title="Conditions">Conditions</a> |
| </h3></div></div></div> |
| <div class="toc"><dl class="toc"> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.conditions.conditions_whats_a_condition">What's |
| A Condition Variable?</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.conditions.conditions_interprocess_conditions">Boost.Interprocess |
| Condition Types And Headers</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.conditions.conditions_anonymous_example">Anonymous |
| condition example</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.conditions.conditions_whats_a_condition"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.conditions.conditions_whats_a_condition" title="What's A Condition Variable?">What's |
| A Condition Variable?</a> |
| </h4></div></div></div> |
| <p> |
| In the previous example, a mutex is used to <span class="emphasis"><em>lock</em></span> but |
| we can't use it to <span class="emphasis"><em>wait</em></span> efficiently until the condition |
| to continue is met. A condition variable can do two things: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| <span class="bold"><strong>wait</strong></span>: The thread is blocked until |
| some other thread notifies that it can continue because the condition |
| that lead to waiting has disappeared. |
| </li> |
| <li class="listitem"> |
| <span class="bold"><strong>notify</strong></span>: The thread sends a signal |
| to one blocked thread or to all blocked threads to tell them that they |
| the condition that provoked their wait has disappeared. |
| </li> |
| </ul></div> |
| <p> |
| Waiting in a condition variable is always associated with a mutex. The |
| mutex must be locked prior to waiting on the condition. When waiting on |
| the condition variable, the thread unlocks the mutex and waits <span class="bold"><strong>atomically</strong></span>. |
| </p> |
| <p> |
| When the thread returns from a wait function (because of a signal or a |
| timeout, for example) the mutex object is again locked. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.conditions.conditions_interprocess_conditions"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.conditions.conditions_interprocess_conditions" title="Boost.Interprocess Condition Types And Headers">Boost.Interprocess |
| Condition Types And Headers</a> |
| </h4></div></div></div> |
| <p> |
| Boost.Interprocess offers the following condition types: |
| </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">sync</span><span class="special">/</span><span class="identifier">interprocess_condition</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/interprocess_condition.html" title="Class interprocess_condition">interprocess_condition</a></code>: |
| An anonymous condition variable that can be placed in shared memory |
| or memory mapped files to be used with <code class="computeroutput"><a class="link" href="../boost/interprocess/interprocess_mutex.html" title="Class interprocess_mutex">boost::interprocess::interprocess_mutex</a></code>. |
| </li></ul></div> |
| <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">sync</span><span class="special">/</span><span class="identifier">interprocess_condition_any</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/interprocess_condition_any.html" title="Class interprocess_condition_any">interprocess_condition_any</a></code>: |
| An anonymous condition variable that can be placed in shared memory |
| or memory mapped files to be used with any lock type. |
| </li></ul></div> |
| <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">sync</span><span class="special">/</span><span class="identifier">named_condition</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/named_condition.html" title="Class named_condition">named_condition</a></code>: |
| A named condition variable to be used with <code class="computeroutput"><a class="link" href="../boost/interprocess/named_mutex.html" title="Class named_mutex">named_mutex</a></code>. |
| </li></ul></div> |
| <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">sync</span><span class="special">/</span><span class="identifier">named_condition_any</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/named_condition.html" title="Class named_condition">named_condition</a></code>: |
| A named condition variable to be used with any lock type. |
| </li></ul></div> |
| <p> |
| Named conditions are similar to anonymous conditions, but they are used |
| in combination with named mutexes. Several times, we don't want to store |
| synchronization objects with the synchronized data: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| We want to change the synchronization method (from interprocess to |
| intra-process, or without any synchronization) using the same data. |
| Storing the process-shared anonymous synchronization with the synchronized |
| data would forbid this. |
| </li> |
| <li class="listitem"> |
| We want to send the synchronized data through the network or any other |
| communication method. Sending the process-shared synchronization objects |
| wouldn't have any sense. |
| </li> |
| </ul></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.conditions.conditions_anonymous_example"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.conditions.conditions_anonymous_example" title="Anonymous condition example">Anonymous |
| condition example</a> |
| </h4></div></div></div> |
| <p> |
| Imagine that a process that writes a trace to a simple shared memory buffer |
| that another process prints one by one. The first process writes the trace |
| and waits until the other process prints the data. To achieve this, we |
| can use two condition variables: the first one is used to block the sender |
| until the second process prints the message and the second one to block |
| the receiver until the buffer has a trace to print. |
| </p> |
| <p> |
| The shared memory trace buffer (doc_anonymous_condition_shared_data.hpp): |
| </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">sync</span><span class="special">/</span><span class="identifier">interprocess_mutex</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">sync</span><span class="special">/</span><span class="identifier">interprocess_condition</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| |
| <span class="keyword">struct</span> <span class="identifier">trace_queue</span> |
| <span class="special">{</span> |
| <span class="keyword">enum</span> <span class="special">{</span> <span class="identifier">LineSize</span> <span class="special">=</span> <span class="number">100</span> <span class="special">};</span> |
| |
| <span class="identifier">trace_queue</span><span class="special">()</span> |
| <span class="special">:</span> <span class="identifier">message_in</span><span class="special">(</span><span class="keyword">false</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">//Mutex to protect access to the queue</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">::</span><span class="identifier">interprocess_mutex</span> <span class="identifier">mutex</span><span class="special">;</span> |
| |
| <span class="comment">//Condition to wait when the queue is empty</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">::</span><span class="identifier">interprocess_condition</span> <span class="identifier">cond_empty</span><span class="special">;</span> |
| |
| <span class="comment">//Condition to wait when the queue is full</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">::</span><span class="identifier">interprocess_condition</span> <span class="identifier">cond_full</span><span class="special">;</span> |
| |
| <span class="comment">//Items to fill</span> |
| <span class="keyword">char</span> <span class="identifier">items</span><span class="special">[</span><span class="identifier">LineSize</span><span class="special">];</span> |
| |
| <span class="comment">//Is there any message</span> |
| <span class="keyword">bool</span> <span class="identifier">message_in</span><span class="special">;</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| This is the process main process. Creates the shared memory, places there |
| the buffer and starts writing messages one by one until it writes "last |
| message" to indicate that there are no more messages to print: |
| </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">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">sync</span><span class="special">/</span><span class="identifier">scoped_lock</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">cstdio</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="string">"doc_anonymous_condition_shared_data.hpp"</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">int</span> <span class="identifier">main</span> <span class="special">()</span> |
| <span class="special">{</span> |
| |
| <span class="comment">//Erase previous shared memory and schedule erasure on exit</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="comment">//only create</span> |
| <span class="special">,</span><span class="string">"MySharedMemory"</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> |
| <span class="keyword">try</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="keyword">sizeof</span><span class="special">(</span><span class="identifier">trace_queue</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="comment">//What to map</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="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="comment">//Construct the shared structure in memory</span> |
| <span class="identifier">trace_queue</span> <span class="special">*</span> <span class="identifier">data</span> <span class="special">=</span> <span class="keyword">new</span> <span class="special">(</span><span class="identifier">addr</span><span class="special">)</span> <span class="identifier">trace_queue</span><span class="special">;</span> |
| |
| <span class="keyword">const</span> <span class="keyword">int</span> <span class="identifier">NumMsg</span> <span class="special">=</span> <span class="number">100</span><span class="special">;</span> |
| |
| <span class="keyword">for</span><span class="special">(</span><span class="keyword">int</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">NumMsg</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">){</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">interprocess_mutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">mutex</span><span class="special">);</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">message_in</span><span class="special">){</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">cond_full</span><span class="special">.</span><span class="identifier">wait</span><span class="special">(</span><span class="identifier">lock</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">i</span> <span class="special">==</span> <span class="special">(</span><span class="identifier">NumMsg</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">sprintf</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">items</span><span class="special">,</span> <span class="string">"%s"</span><span class="special">,</span> <span class="string">"last message"</span><span class="special">);</span> |
| <span class="keyword">else</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">sprintf</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">items</span><span class="special">,</span> <span class="string">"%s_%d"</span><span class="special">,</span> <span class="string">"my_trace"</span><span class="special">,</span> <span class="identifier">i</span><span class="special">);</span> |
| |
| <span class="comment">//Notify to the other process that there is a message</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">cond_empty</span><span class="special">.</span><span class="identifier">notify_one</span><span class="special">();</span> |
| |
| <span class="comment">//Mark message buffer as full</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">message_in</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">;</span> |
| <span class="special">}</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> |
| The second process opens the shared memory and prints each message until |
| the "last message" message is received: |
| </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">boost</span><span class="special">/</span><span class="identifier">interprocess</span><span class="special">/</span><span class="identifier">sync</span><span class="special">/</span><span class="identifier">scoped_lock</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="preprocessor">#include</span> <span class="string">"doc_anonymous_condition_shared_data.hpp"</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">int</span> <span class="identifier">main</span> <span class="special">()</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">open_only</span> <span class="comment">//only create</span> |
| <span class="special">,</span><span class="string">"MySharedMemory"</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> |
| |
| <span class="keyword">try</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="comment">//What to map</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="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="comment">//Obtain a pointer to the shared structure</span> |
| <span class="identifier">trace_queue</span> <span class="special">*</span> <span class="identifier">data</span> <span class="special">=</span> <span class="keyword">static_cast</span><span class="special"><</span><span class="identifier">trace_queue</span><span class="special">*>(</span><span class="identifier">addr</span><span class="special">);</span> |
| |
| <span class="comment">//Print messages until the other process marks the end</span> |
| <span class="keyword">bool</span> <span class="identifier">end_loop</span> <span class="special">=</span> <span class="keyword">false</span><span class="special">;</span> |
| <span class="keyword">do</span><span class="special">{</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">interprocess_mutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">mutex</span><span class="special">);</span> |
| <span class="keyword">if</span><span class="special">(!</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">message_in</span><span class="special">){</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">cond_empty</span><span class="special">.</span><span class="identifier">wait</span><span class="special">(</span><span class="identifier">lock</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">strcmp</span><span class="special">(</span><span class="identifier">data</span><span class="special">-></span><span class="identifier">items</span><span class="special">,</span> <span class="string">"last message"</span><span class="special">)</span> <span class="special">==</span> <span class="number">0</span><span class="special">){</span> |
| <span class="identifier">end_loop</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="keyword">else</span><span class="special">{</span> |
| <span class="comment">//Print the message</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">data</span><span class="special">-></span><span class="identifier">items</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="comment">//Notify the other process that the buffer is empty</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">message_in</span> <span class="special">=</span> <span class="keyword">false</span><span class="special">;</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">cond_full</span><span class="special">.</span><span class="identifier">notify_one</span><span class="special">();</span> |
| <span class="special">}</span> |
| <span class="special">}</span> |
| <span class="keyword">while</span><span class="special">(!</span><span class="identifier">end_loop</span><span class="special">);</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> |
| With condition variables, a process can block if it can't continue the |
| work, and when the conditions to continue are met another process can wake |
| it. |
| </p> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="interprocess.synchronization_mechanisms.semaphores"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.semaphores" title="Semaphores">Semaphores</a> |
| </h3></div></div></div> |
| <div class="toc"><dl class="toc"> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.semaphores.semaphores_whats_a_semaphores">What's |
| A Semaphore?</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.semaphores.semaphores_interprocess_semaphores">Boost.Interprocess |
| Semaphore Types And Headers</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.semaphores.semaphores_anonymous_example">Anonymous |
| semaphore example</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.semaphores.semaphores_whats_a_semaphores"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.semaphores.semaphores_whats_a_semaphores" title="What's A Semaphore?">What's |
| A Semaphore?</a> |
| </h4></div></div></div> |
| <p> |
| A semaphore is a synchronization mechanism between processes based in an |
| internal count that offers two basic operations: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| <span class="bold"><strong>Wait</strong></span>: Tests the value of the semaphore |
| count, and waits if the value is less than or equal than 0. Otherwise, |
| decrements the semaphore count. |
| </li> |
| <li class="listitem"> |
| <span class="bold"><strong>Post</strong></span>: Increments the semaphore count. |
| If any process is blocked, one of those processes is awoken. |
| </li> |
| </ul></div> |
| <p> |
| If the initial semaphore count is initialized to 1, a <span class="bold"><strong>Wait</strong></span> |
| operation is equivalent to a mutex locking and <span class="bold"><strong>Post</strong></span> |
| is equivalent to a mutex unlocking. This type of semaphore is known as |
| a <span class="bold"><strong>binary semaphore</strong></span>. |
| </p> |
| <p> |
| Although semaphores can be used like mutexes, they have a unique feature: |
| unlike mutexes, a <span class="bold"><strong>Post</strong></span> operation need |
| not be executed by the same thread/process that executed the <span class="bold"><strong>Wait</strong></span> operation. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.semaphores.semaphores_interprocess_semaphores"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.semaphores.semaphores_interprocess_semaphores" title="Boost.Interprocess Semaphore Types And Headers">Boost.Interprocess |
| Semaphore Types And Headers</a> |
| </h4></div></div></div> |
| <p> |
| Boost.Interprocess offers the following semaphore types: |
| </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">sync</span><span class="special">/</span><span class="identifier">interprocess_semaphore</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/interprocess_semaphore.html" title="Class interprocess_semaphore">interprocess_semaphore</a></code>: |
| An anonymous semaphore that can be placed in shared memory or memory |
| mapped files. |
| </li></ul></div> |
| <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">sync</span><span class="special">/</span><span class="identifier">named_semaphore</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/named_semaphore.html" title="Class named_semaphore">named_semaphore</a></code>: |
| A named semaphore. |
| </li></ul></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.semaphores.semaphores_anonymous_example"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.semaphores.semaphores_anonymous_example" title="Anonymous semaphore example">Anonymous |
| semaphore example</a> |
| </h4></div></div></div> |
| <p> |
| We will implement an integer array in shared memory that will be used to |
| transfer data from one process to another process. The first process will |
| write some integers to the array and the process will block if the array |
| is full. |
| </p> |
| <p> |
| The second process will copy the transmitted data to its own buffer, blocking |
| if there is no new data in the buffer. |
| </p> |
| <p> |
| This is the shared integer array (doc_anonymous_semaphore_shared_data.hpp): |
| </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">sync</span><span class="special">/</span><span class="identifier">interprocess_semaphore</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| |
| <span class="keyword">struct</span> <span class="identifier">shared_memory_buffer</span> |
| <span class="special">{</span> |
| <span class="keyword">enum</span> <span class="special">{</span> <span class="identifier">NumItems</span> <span class="special">=</span> <span class="number">10</span> <span class="special">};</span> |
| |
| <span class="identifier">shared_memory_buffer</span><span class="special">()</span> |
| <span class="special">:</span> <span class="identifier">mutex</span><span class="special">(</span><span class="number">1</span><span class="special">),</span> <span class="identifier">nempty</span><span class="special">(</span><span class="identifier">NumItems</span><span class="special">),</span> <span class="identifier">nstored</span><span class="special">(</span><span class="number">0</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">//Semaphores to protect and synchronize access</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">::</span><span class="identifier">interprocess_semaphore</span> |
| <span class="identifier">mutex</span><span class="special">,</span> <span class="identifier">nempty</span><span class="special">,</span> <span class="identifier">nstored</span><span class="special">;</span> |
| |
| <span class="comment">//Items to fill</span> |
| <span class="keyword">int</span> <span class="identifier">items</span><span class="special">[</span><span class="identifier">NumItems</span><span class="special">];</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| This is the process main process. Creates the shared memory, places there |
| the integer array and starts integers one by one, blocking if the array |
| is full: |
| </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">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="string">"doc_anonymous_semaphore_shared_data.hpp"</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">int</span> <span class="identifier">main</span> <span class="special">()</span> |
| <span class="special">{</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="comment">//only create</span> |
| <span class="special">,</span><span class="string">"MySharedMemory"</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> |
| |
| <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="keyword">sizeof</span><span class="special">(</span><span class="identifier">shared_memory_buffer</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="comment">//What to map</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="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="comment">//Construct the shared structure in memory</span> |
| <span class="identifier">shared_memory_buffer</span> <span class="special">*</span> <span class="identifier">data</span> <span class="special">=</span> <span class="keyword">new</span> <span class="special">(</span><span class="identifier">addr</span><span class="special">)</span> <span class="identifier">shared_memory_buffer</span><span class="special">;</span> |
| |
| <span class="keyword">const</span> <span class="keyword">int</span> <span class="identifier">NumMsg</span> <span class="special">=</span> <span class="number">100</span><span class="special">;</span> |
| |
| <span class="comment">//Insert data in the array</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="keyword">int</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">NumMsg</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">){</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">nempty</span><span class="special">.</span><span class="identifier">wait</span><span class="special">();</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">mutex</span><span class="special">.</span><span class="identifier">wait</span><span class="special">();</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">items</span><span class="special">[</span><span class="identifier">i</span> <span class="special">%</span> <span class="identifier">shared_memory_buffer</span><span class="special">::</span><span class="identifier">NumItems</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">i</span><span class="special">;</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">mutex</span><span class="special">.</span><span class="identifier">post</span><span class="special">();</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">nstored</span><span class="special">.</span><span class="identifier">post</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> |
| The second process opens the shared memory and copies the received integers |
| to it's own buffer: |
| </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">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="string">"doc_anonymous_semaphore_shared_data.hpp"</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">int</span> <span class="identifier">main</span> <span class="special">()</span> |
| <span class="special">{</span> |
| <span class="comment">//Remove shared memory on destruction</span> |
| <span class="keyword">struct</span> <span class="identifier">shm_remove</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">open_only</span> <span class="comment">//only create</span> |
| <span class="special">,</span><span class="string">"MySharedMemory"</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> |
| |
| <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="comment">//What to map</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="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="comment">//Obtain the shared structure</span> |
| <span class="identifier">shared_memory_buffer</span> <span class="special">*</span> <span class="identifier">data</span> <span class="special">=</span> <span class="keyword">static_cast</span><span class="special"><</span><span class="identifier">shared_memory_buffer</span><span class="special">*>(</span><span class="identifier">addr</span><span class="special">);</span> |
| |
| <span class="keyword">const</span> <span class="keyword">int</span> <span class="identifier">NumMsg</span> <span class="special">=</span> <span class="number">100</span><span class="special">;</span> |
| |
| <span class="keyword">int</span> <span class="identifier">extracted_data</span> <span class="special">[</span><span class="identifier">NumMsg</span><span class="special">];</span> |
| |
| <span class="comment">//Extract the data</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="keyword">int</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">NumMsg</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">){</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">nstored</span><span class="special">.</span><span class="identifier">wait</span><span class="special">();</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">mutex</span><span class="special">.</span><span class="identifier">wait</span><span class="special">();</span> |
| <span class="identifier">extracted_data</span><span class="special">[</span><span class="identifier">i</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">data</span><span class="special">-></span><span class="identifier">items</span><span class="special">[</span><span class="identifier">i</span> <span class="special">%</span> <span class="identifier">shared_memory_buffer</span><span class="special">::</span><span class="identifier">NumItems</span><span class="special">];</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">mutex</span><span class="special">.</span><span class="identifier">post</span><span class="special">();</span> |
| <span class="identifier">data</span><span class="special">-></span><span class="identifier">nempty</span><span class="special">.</span><span class="identifier">post</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> |
| The same interprocess communication can be achieved with a condition variables |
| and mutexes, but for several synchronization patterns, a semaphore is more |
| efficient than a mutex/condition combination. |
| </p> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes" title="Sharable and Upgradable Mutexes">Sharable |
| and Upgradable Mutexes</a> |
| </h3></div></div></div> |
| <div class="toc"><dl class="toc"> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.upgradable_whats_a_mutex">What's |
| a Sharable and an Upgradable Mutex?</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.upgradable_transitions">Lock |
| transitions for Upgradable Mutex</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations">Upgradable |
| Mutex Operations</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_mutex_interprocess_mutexes">Boost.Interprocess |
| Sharable & Upgradable Mutex Types And Headers</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_locks">Sharable |
| Lock And Upgradable Lock</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.upgradable_whats_a_mutex"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.upgradable_whats_a_mutex" title="What's a Sharable and an Upgradable Mutex?">What's |
| a Sharable and an Upgradable Mutex?</a> |
| </h4></div></div></div> |
| <p> |
| Sharable and upgradable mutex are special mutex types that offers more |
| locking possibilities than a normal mutex. Sometimes, we can distinguish |
| between <span class="bold"><strong>reading</strong></span> the data and <span class="bold"><strong>modifying</strong></span> the data. If just some threads need to |
| modify the data, and a plain mutex is used to protect the data from concurrent |
| access, concurrency is pretty limited: two threads that only read the data |
| will be serialized instead of being executed concurrently. |
| </p> |
| <p> |
| If we allow concurrent access to threads that just read the data but we |
| avoid concurrent access between threads that read and modify or between |
| threads that modify, we can increase performance. This is specially true |
| in applications where data reading is more common than data modification |
| and the synchronized data reading code needs some time to execute. With |
| a sharable mutex we can acquire 2 lock types: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| <span class="bold"><strong>Exclusive lock</strong></span>: Similar to a plain |
| mutex. If a thread acquires an exclusive lock, no other thread can |
| acquire any lock (exclusive or other) until the exclusive lock is released. |
| If any thread other has any lock other than exclusive, a thread trying |
| to acquire an exclusive lock will block. This lock will be acquired |
| by threads that will modify the data. |
| </li> |
| <li class="listitem"> |
| <span class="bold"><strong>Sharable lock</strong></span>: If a thread acquires |
| a sharable lock, other threads can't acquire the exclusive lock. If |
| any thread has acquired the exclusive lock a thread trying to acquire |
| a sharable lock will block. This locking is executed by threads that |
| just need to read the data. |
| </li> |
| </ul></div> |
| <p> |
| With an upgradable mutex we can acquire previous locks plus a new upgradable |
| lock: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <span class="bold"><strong>Upgradable lock</strong></span>: Acquiring an upgradable |
| lock is similar to acquiring a <span class="bold"><strong>privileged sharable |
| lock</strong></span>. If a thread acquires an upgradable lock, other threads |
| can acquire a sharable lock. If any thread has acquired the exclusive |
| or upgradable lock a thread trying to acquire an upgradable lock will |
| block. A thread that has acquired an upgradable lock, is guaranteed |
| to be able to acquire atomically an exclusive lock when other threads |
| that have acquired a sharable lock release it. This is used for a thread |
| that <span class="bold"><strong>maybe</strong></span> needs to modify the data, |
| but usually just needs to read the data. This thread acquires the upgradable |
| lock and other threads can acquire the sharable lock. If the upgradable |
| thread reads the data and it has to modify it, the thread can be promoted |
| to acquire the exclusive lock: when all sharable threads have released |
| the sharable lock, the upgradable lock is atomically promoted to an |
| exclusive lock. The newly promoted thread can modify the data and it |
| can be sure that no other thread has modified it while doing the transition. |
| <span class="bold"><strong>Only 1 thread can acquire the upgradable (privileged |
| reader) lock</strong></span>. |
| </li></ul></div> |
| <p> |
| To sum up: |
| </p> |
| <div class="table"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.upgradable_whats_a_mutex.t0"></a><p class="title"><b>Table 14.5. Locking Possibilities for a Sharable Mutex</b></p> |
| <div class="table-contents"><table class="table" summary="Locking Possibilities for a Sharable Mutex"> |
| <colgroup> |
| <col> |
| <col> |
| </colgroup> |
| <thead><tr> |
| <th> |
| <p> |
| If a thread has acquired the... |
| </p> |
| </th> |
| <th> |
| <p> |
| Other threads can acquire... |
| </p> |
| </th> |
| </tr></thead> |
| <tbody> |
| <tr> |
| <td> |
| <p> |
| Sharable lock |
| </p> |
| </td> |
| <td> |
| <p> |
| many sharable locks |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Exclusive lock |
| </p> |
| </td> |
| <td> |
| <p> |
| no locks |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table></div> |
| </div> |
| <br class="table-break"><div class="table"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.upgradable_whats_a_mutex.t1"></a><p class="title"><b>Table 14.6. Locking Possibilities for an Upgradable Mutex</b></p> |
| <div class="table-contents"><table class="table" summary="Locking Possibilities for an Upgradable Mutex"> |
| <colgroup> |
| <col> |
| <col> |
| </colgroup> |
| <thead><tr> |
| <th> |
| <p> |
| If a thread has acquired the... |
| </p> |
| </th> |
| <th> |
| <p> |
| Other threads can acquire... |
| </p> |
| </th> |
| </tr></thead> |
| <tbody> |
| <tr> |
| <td> |
| <p> |
| Sharable lock |
| </p> |
| </td> |
| <td> |
| <p> |
| many sharable locks and 1 upgradable lock |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Upgradable lock |
| </p> |
| </td> |
| <td> |
| <p> |
| many sharable locks |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Exclusive lock |
| </p> |
| </td> |
| <td> |
| <p> |
| no locks |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table></div> |
| </div> |
| <br class="table-break"> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.upgradable_transitions"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.upgradable_transitions" title="Lock transitions for Upgradable Mutex">Lock |
| transitions for Upgradable Mutex</a> |
| </h4></div></div></div> |
| <p> |
| A sharable mutex has no option to change the acquired lock for another |
| lock atomically. |
| </p> |
| <p> |
| On the other hand, for an upgradable mutex, a thread that has acquired |
| a lock can try to acquire another lock type atomically. All lock transitions |
| are not guaranteed to succeed. Even if a transition is guaranteed to succeed, |
| some transitions will block the thread waiting until other threads release |
| the sharable locks. <span class="bold"><strong>Atomically</strong></span> means that |
| no other thread will acquire an Upgradable or Exclusive lock in the transition, |
| <span class="bold"><strong>so data is guaranteed to remain unchanged</strong></span>: |
| </p> |
| <div class="table"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.upgradable_transitions.t0"></a><p class="title"><b>Table 14.7. Transition Possibilities for an Upgradable Mutex</b></p> |
| <div class="table-contents"><table class="table" summary="Transition Possibilities for an Upgradable Mutex"> |
| <colgroup> |
| <col> |
| <col> |
| </colgroup> |
| <thead><tr> |
| <th> |
| <p> |
| If a thread has acquired the... |
| </p> |
| </th> |
| <th> |
| <p> |
| It can atomically release the previous lock and... |
| </p> |
| </th> |
| </tr></thead> |
| <tbody> |
| <tr> |
| <td> |
| <p> |
| Sharable lock |
| </p> |
| </td> |
| <td> |
| <p> |
| try to obtain (not guaranteed) immediately the Exclusive lock |
| if no other thread has exclusive or upgrable lock |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Sharable lock |
| </p> |
| </td> |
| <td> |
| <p> |
| try to obtain (not guaranteed) immediately the Upgradable lock |
| if no other thread has exclusive or upgrable lock |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Upgradable lock |
| </p> |
| </td> |
| <td> |
| <p> |
| obtain the Exclusive lock when all sharable locks are released |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Upgradable lock |
| </p> |
| </td> |
| <td> |
| <p> |
| obtain the Sharable lock immediately |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Exclusive lock |
| </p> |
| </td> |
| <td> |
| <p> |
| obtain the Upgradable lock immediately |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Exclusive lock |
| </p> |
| </td> |
| <td> |
| <p> |
| obtain the Sharable lock immediately |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table></div> |
| </div> |
| <br class="table-break"><p> |
| As we can see, an upgradable mutex is a powerful synchronization utility |
| that can improve the concurrency. However, if most of the time we have |
| to modify the data, or the synchronized code section is very short, it's |
| more efficient to use a plain mutex, since it has less overhead. Upgradable |
| lock shines when the synchronized code section is bigger and there are |
| more readers than modifiers. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations" title="Upgradable Mutex Operations">Upgradable |
| Mutex Operations</a> |
| </h4></div></div></div> |
| <div class="toc"><dl class="toc"> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.sharable_upgradable_mutexes_operations_exclusive">Exclusive |
| Locking (Sharable & Upgradable Mutexes)</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.sharable_upgradable_mutexes_operations_sharable">Sharable |
| Locking (Sharable & Upgradable Mutexes)</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.upgradable_mutexes_operations_upgradable">Upgradable |
| Locking (Upgradable Mutex only)</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.upgradable_mutexes_operations_demotions">Demotions |
| (Upgradable Mutex only)</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.upgradable_mutexes_operations_promotions">Promotions |
| (Upgradable Mutex only)</a></span></dt> |
| </dl></div> |
| <p> |
| All the upgradable mutex types from <span class="bold"><strong>Boost.Interprocess</strong></span> |
| implement the following operations: |
| </p> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.sharable_upgradable_mutexes_operations_exclusive"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.sharable_upgradable_mutexes_operations_exclusive" title="Exclusive Locking (Sharable & Upgradable Mutexes)">Exclusive |
| Locking (Sharable & Upgradable Mutexes)</a> |
| </h5></div></div></div> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void lock()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to |
| obtain exclusive ownership of the mutex, and if another thread has any |
| ownership of the mutex (exclusive or other), it waits until it can obtain |
| the ownership. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool try_lock()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to |
| acquire exclusive ownership of the mutex without waiting. If no other |
| thread has any ownership of the mutex (exclusive or other) this succeeds. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If it can acquire exclusive |
| ownership immediately returns true. If it has to wait, returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool timed_lock(const boost::posix_time::ptime |
| &abs_time)</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to |
| acquire exclusive ownership of the mutex waiting if necessary until no |
| other thread has any ownership of the mutex (exclusive or other) or abs_time |
| is reached. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If acquires exclusive ownership, |
| returns true. Otherwise returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void unlock()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have exclusive |
| ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread releases |
| the exclusive ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.sharable_upgradable_mutexes_operations_sharable"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.sharable_upgradable_mutexes_operations_sharable" title="Sharable Locking (Sharable & Upgradable Mutexes)">Sharable |
| Locking (Sharable & Upgradable Mutexes)</a> |
| </h5></div></div></div> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void lock_sharable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to |
| obtain sharable ownership of the mutex, and if another thread has exclusive |
| ownership of the mutex, waits until it can obtain the ownership. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool try_lock_sharable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to |
| acquire sharable ownership of the mutex without waiting. If no other |
| thread has exclusive ownership of the mutex this succeeds. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If it can acquire sharable |
| ownership immediately returns true. If it has to wait, returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool timed_lock_sharable(const boost::posix_time::ptime |
| &abs_time)</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to |
| acquire sharable ownership of the mutex waiting if necessary until no |
| other thread has exclusive ownership of the mutex or abs_time is reached. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If acquires sharable ownership, |
| returns true. Otherwise returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void unlock_sharable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have sharable |
| ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread releases |
| the sharable ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.upgradable_mutexes_operations_upgradable"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.upgradable_mutexes_operations_upgradable" title="Upgradable Locking (Upgradable Mutex only)">Upgradable |
| Locking (Upgradable Mutex only)</a> |
| </h5></div></div></div> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void lock_upgradable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to |
| obtain upgradable ownership of the mutex, and if another thread has exclusive |
| or upgradable ownership of the mutex, waits until it can obtain the ownership. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool try_lock_upgradable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to |
| acquire upgradable ownership of the mutex without waiting. If no other |
| thread has exclusive or upgradable ownership of the mutex this succeeds. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If it can acquire upgradable |
| ownership immediately returns true. If it has to wait, returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool timed_lock_upgradable(const boost::posix_time::ptime |
| &abs_time)</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to |
| acquire upgradable ownership of the mutex waiting if necessary until |
| no other thread has exclusive ownership of the mutex or abs_time is reached. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If acquires upgradable ownership, |
| returns true. Otherwise returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void unlock_upgradable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have upgradable |
| ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread releases |
| the upgradable ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.upgradable_mutexes_operations_demotions"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.upgradable_mutexes_operations_demotions" title="Demotions (Upgradable Mutex only)">Demotions |
| (Upgradable Mutex only)</a> |
| </h5></div></div></div> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void unlock_and_lock_upgradable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have exclusive |
| ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The thread atomically releases |
| exclusive ownership and acquires upgradable ownership. This operation |
| is non-blocking. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void unlock_and_lock_sharable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have exclusive |
| ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The thread atomically releases |
| exclusive ownership and acquires sharable ownership. This operation is |
| non-blocking. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void unlock_upgradable_and_lock_sharable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have upgradable |
| ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The thread atomically releases |
| upgradable ownership and acquires sharable ownership. This operation |
| is non-blocking. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.upgradable_mutexes_operations_promotions"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_operations.upgradable_mutexes_operations_promotions" title="Promotions (Upgradable Mutex only)">Promotions |
| (Upgradable Mutex only)</a> |
| </h5></div></div></div> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void unlock_upgradable_and_lock()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have upgradable |
| ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The thread atomically releases |
| upgradable ownership and acquires exclusive ownership. This operation |
| will block until all threads with sharable ownership release it. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool try_unlock_upgradable_and_lock()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have upgradable |
| ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The thread atomically releases |
| upgradable ownership and tries to acquire exclusive ownership. This operation |
| will fail if there are threads with sharable ownership, but it will maintain |
| upgradable ownership. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If acquires exclusive ownership, |
| returns true. Otherwise returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool timed_unlock_upgradable_and_lock(const |
| boost::posix_time::ptime &abs_time)</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have upgradable |
| ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The thread atomically releases |
| upgradable ownership and tries to acquire exclusive ownership, waiting |
| if necessary until abs_time. This operation will fail if there are threads |
| with sharable ownership or timeout reaches, but it will maintain upgradable |
| ownership. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If acquires exclusive ownership, |
| returns true. Otherwise returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool try_unlock_sharable_and_lock()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have sharable |
| ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The thread atomically releases |
| sharable ownership and tries to acquire exclusive ownership. This operation |
| will fail if there are threads with sharable or upgradable ownership, |
| but it will maintain sharable ownership. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If acquires exclusive ownership, |
| returns true. Otherwise returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool try_unlock_sharable_and_lock_upgradable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have sharable |
| ownership of the mutex. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The thread atomically releases |
| sharable ownership and tries to acquire upgradable ownership. This operation |
| will fail if there are threads with sharable or upgradable ownership, |
| but it will maintain sharable ownership. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If acquires upgradable ownership, |
| returns true. Otherwise returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| <div class="important"><table border="0" summary="Important"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../doc/src/images/important.png"></td> |
| <th align="left">Important</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">ptime</span></code> absolute time points used by |
| Boost.Interprocess synchronization mechanisms are UTC time points, |
| not local time points |
| </p></td></tr> |
| </table></div> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_mutex_interprocess_mutexes"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_mutexes_mutex_interprocess_mutexes" title="Boost.Interprocess Sharable & Upgradable Mutex Types And Headers">Boost.Interprocess |
| Sharable & Upgradable Mutex Types And Headers</a> |
| </h4></div></div></div> |
| <p> |
| Boost.Interprocess offers the following sharable mutex types: |
| </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">sync</span><span class="special">/</span><span class="identifier">interprocess_sharable_mutex</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/interprocess_s_idp56636288.html" title="Class interprocess_sharable_mutex">interprocess_sharable_mutex</a></code>: |
| A non-recursive, anonymous sharable mutex that can be placed in shared |
| memory or memory mapped files. |
| </li></ul></div> |
| <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">sync</span><span class="special">/</span><span class="identifier">named_sharable_mutex</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/named_sharable_mutex.html" title="Class named_sharable_mutex">named_sharable_mutex</a></code>: |
| A non-recursive, named sharable mutex. |
| </li></ul></div> |
| <p> |
| Boost.Interprocess offers the following upgradable mutex types: |
| </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">sync</span><span class="special">/</span><span class="identifier">interprocess_upgradable_mutex</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/interprocess_u_idp56667104.html" title="Class interprocess_upgradable_mutex">interprocess_upgradable_mutex</a></code>: |
| A non-recursive, anonymous upgradable mutex that can be placed in shared |
| memory or memory mapped files. |
| </li></ul></div> |
| <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">sync</span><span class="special">/</span><span class="identifier">named_upgradable_mutex</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/named_upgradable_mutex.html" title="Class named_upgradable_mutex">named_upgradable_mutex</a></code>: |
| A non-recursive, named upgradable mutex. |
| </li></ul></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_locks"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_locks" title="Sharable Lock And Upgradable Lock">Sharable |
| Lock And Upgradable Lock</a> |
| </h4></div></div></div> |
| <div class="toc"><dl class="toc"><dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_locks.upgradable_mutexes_lock_types">Sharable |
| Lock And Upgradable Lock Headers</a></span></dt></dl></div> |
| <p> |
| As with plain mutexes, it's important to release the acquired lock even |
| in the presence of exceptions. <span class="bold"><strong>Boost.Interprocess</strong></span> |
| mutexes are best used with the <code class="computeroutput"><a class="link" href="../boost/interprocess/scoped_lock.html" title="Class template scoped_lock">scoped_lock</a></code> |
| utility, and this class only offers exclusive locking. |
| </p> |
| <p> |
| As we have sharable locking and upgradable locking with upgradable mutexes, |
| we have two new utilities: <code class="computeroutput"><a class="link" href="../boost/interprocess/sharable_lock.html" title="Class template sharable_lock">sharable_lock</a></code> |
| and <code class="computeroutput"><a class="link" href="../boost/interprocess/upgradable_lock.html" title="Class template upgradable_lock">upgradable_lock</a></code>. |
| Both classes are similar to <code class="computeroutput"><span class="identifier">scoped_lock</span></code> |
| but <code class="computeroutput"><span class="identifier">sharable_lock</span></code> acquires |
| the sharable lock in the constructor and <code class="computeroutput"><span class="identifier">upgradable_lock</span></code> |
| acquires the upgradable lock in the constructor. |
| </p> |
| <p> |
| These two utilities can be use with any synchronization object that offers |
| the needed operations. For example, a user defined mutex type with no upgradable |
| locking features can use <code class="computeroutput"><span class="identifier">sharable_lock</span></code> |
| if the synchronization object offers <span class="bold"><strong>lock_sharable()</strong></span> |
| and <span class="bold"><strong>unlock_sharable()</strong></span> operations: |
| </p> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_locks.upgradable_mutexes_lock_types"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.sharable_upgradable_mutexes.sharable_upgradable_locks.upgradable_mutexes_lock_types" title="Sharable Lock And Upgradable Lock Headers">Sharable |
| Lock And Upgradable Lock Headers</a> |
| </h5></div></div></div> |
| <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">sync</span><span class="special">/</span><span class="identifier">sharable_lock</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <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">sync</span><span class="special">/</span><span class="identifier">upgradable_lock</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| </div> |
| <p> |
| <code class="computeroutput"><span class="identifier">sharable_lock</span></code> calls <span class="bold"><strong>unlock_sharable()</strong></span> in its destructor, and <code class="computeroutput"><span class="identifier">upgradable_lock</span></code> calls <span class="bold"><strong>unlock_upgradable()</strong></span> |
| in its destructor, so the upgradable mutex is always unlocked when an exception |
| occurs. |
| </p> |
| <pre class="programlisting"><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="identifier">SharableOrUpgradableMutex</span> <span class="identifier">sh_or_up_mutex</span><span class="special">;</span> |
| |
| <span class="special">{</span> |
| <span class="comment">//This will call lock_sharable()</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">SharableOrUpgradableMutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">sh_or_up_mutex</span><span class="special">);</span> |
| |
| <span class="comment">//Some code</span> |
| |
| <span class="comment">//The mutex will be unlocked here</span> |
| <span class="special">}</span> |
| |
| <span class="special">{</span> |
| <span class="comment">//This won't lock the mutex()</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">SharableOrUpgradableMutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">sh_or_up_mutex</span><span class="special">,</span> <span class="identifier">defer_lock</span><span class="special">);</span> |
| |
| <span class="comment">//Lock it on demand. This will call lock_sharable()</span> |
| <span class="identifier">lock</span><span class="special">.</span><span class="identifier">lock</span><span class="special">();</span> |
| |
| <span class="comment">//Some code</span> |
| |
| <span class="comment">//The mutex will be unlocked here</span> |
| <span class="special">}</span> |
| |
| <span class="special">{</span> |
| <span class="comment">//This will call try_lock_sharable()</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">SharableOrUpgradableMutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">sh_or_up_mutex</span><span class="special">,</span> <span class="identifier">try_to_lock</span><span class="special">);</span> |
| |
| <span class="comment">//Check if the mutex has been successfully locked</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">lock</span><span class="special">){</span> |
| <span class="comment">//Some code</span> |
| <span class="special">}</span> |
| <span class="comment">//If the mutex was locked it will be unlocked</span> |
| <span class="special">}</span> |
| |
| <span class="special">{</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">ptime</span> <span class="identifier">abs_time</span> <span class="special">=</span> <span class="special">...</span> |
| |
| <span class="comment">//This will call timed_lock_sharable()</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">SharableOrUpgradableMutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">sh_or_up_mutex</span><span class="special">,</span> <span class="identifier">abs_time</span><span class="special">);</span> |
| |
| <span class="comment">//Check if the mutex has been successfully locked</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">lock</span><span class="special">){</span> |
| <span class="comment">//Some code</span> |
| <span class="special">}</span> |
| <span class="comment">//If the mutex was locked it will be unlocked</span> |
| <span class="special">}</span> |
| |
| <span class="identifier">UpgradableMutex</span> <span class="identifier">up_mutex</span><span class="special">;</span> |
| |
| <span class="special">{</span> |
| <span class="comment">//This will call lock_upgradable()</span> |
| <span class="identifier">upgradable_lock</span><span class="special"><</span><span class="identifier">UpgradableMutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">up_mutex</span><span class="special">);</span> |
| |
| <span class="comment">//Some code</span> |
| |
| <span class="comment">//The mutex will be unlocked here</span> |
| <span class="special">}</span> |
| |
| <span class="special">{</span> |
| <span class="comment">//This won't lock the mutex()</span> |
| <span class="identifier">upgradable_lock</span><span class="special"><</span><span class="identifier">UpgradableMutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">up_mutex</span><span class="special">,</span> <span class="identifier">defer_lock</span><span class="special">);</span> |
| |
| <span class="comment">//Lock it on demand. This will call lock_upgradable()</span> |
| <span class="identifier">lock</span><span class="special">.</span><span class="identifier">lock</span><span class="special">();</span> |
| |
| <span class="comment">//Some code</span> |
| |
| <span class="comment">//The mutex will be unlocked here</span> |
| <span class="special">}</span> |
| |
| <span class="special">{</span> |
| <span class="comment">//This will call try_lock_upgradable()</span> |
| <span class="identifier">upgradable_lock</span><span class="special"><</span><span class="identifier">UpgradableMutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">up_mutex</span><span class="special">,</span> <span class="identifier">try_to_lock</span><span class="special">);</span> |
| |
| <span class="comment">//Check if the mutex has been successfully locked</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">lock</span><span class="special">){</span> |
| <span class="comment">//Some code</span> |
| <span class="special">}</span> |
| <span class="comment">//If the mutex was locked it will be unlocked</span> |
| <span class="special">}</span> |
| |
| <span class="special">{</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">ptime</span> <span class="identifier">abs_time</span> <span class="special">=</span> <span class="special">...</span> |
| |
| <span class="comment">//This will call timed_lock_upgradable()</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">UpgradableMutex</span><span class="special">></span> <span class="identifier">lock</span><span class="special">(</span><span class="identifier">up_mutex</span><span class="special">,</span> <span class="identifier">abs_time</span><span class="special">);</span> |
| |
| <span class="comment">//Check if the mutex has been successfully locked</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">lock</span><span class="special">){</span> |
| <span class="comment">//Some code</span> |
| <span class="special">}</span> |
| <span class="comment">//If the mutex was locked it will be unlocked</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/upgradable_lock.html" title="Class template upgradable_lock">upgradable_lock</a></code> |
| and <code class="computeroutput"><a class="link" href="../boost/interprocess/sharable_lock.html" title="Class template sharable_lock">sharable_lock</a></code> |
| offer more features and operations, see their reference for more informations |
| </p> |
| <div class="important"><table border="0" summary="Important"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../doc/src/images/important.png"></td> |
| <th align="left">Important</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">ptime</span></code> absolute time points used by |
| Boost.Interprocess synchronization mechanisms are UTC time points, not |
| local time points |
| </p></td></tr> |
| </table></div> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="interprocess.synchronization_mechanisms.lock_conversions"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions" title="Lock Transfers Through Move Semantics">Lock |
| Transfers Through Move Semantics</a> |
| </h3></div></div></div> |
| <div class="toc"><dl class="toc"> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_simple_transfer">Simple |
| Lock Transfer</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_summary">Lock |
| Transfer Summary</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_not_locked">Transferring |
| Unlocked Locks</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_failure">Transfer |
| Failures</a></span></dt> |
| </dl></div> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="bold"><strong>Interprocess uses its own move semantics emulation |
| code for compilers that don't support rvalues references. This is a temporary |
| solution until a Boost move semantics library is accepted.</strong></span> |
| </p> |
| </div> |
| <p> |
| Scoped locks and similar utilities offer simple resource management possibilities, |
| but with advanced mutex types like upgradable mutexes, there are operations |
| where an acquired lock type is released and another lock type is acquired |
| atomically. This is implemented by upgradable mutex operations like <code class="computeroutput"><span class="identifier">unlock_and_lock_sharable</span><span class="special">()</span></code>. |
| </p> |
| <p> |
| These operations can be managed more effectively using <span class="bold"><strong>lock |
| transfer operations</strong></span>. A lock transfer operations explicitly indicates |
| that a mutex owned by a lock is transferred to another lock executing atomic |
| unlocking plus locking operations. |
| </p> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_simple_transfer"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_simple_transfer" title="Simple Lock Transfer">Simple |
| Lock Transfer</a> |
| </h4></div></div></div> |
| <p> |
| Imagine that a thread modifies some data in the beginning but after that, |
| it has to just read it in a long time. The code can acquire the exclusive |
| lock, modify the data and atomically release the exclusive lock and acquire |
| the sharable lock. With these sequence we guarantee that no other thread |
| can modify the data in the transition and that more readers can acquire |
| sharable lock, increasing concurrency. Without lock transfer operations, |
| this would be coded like this: |
| </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">interprocess_upgradable_mutex</span> <span class="identifier">mutex</span><span class="special">;</span> |
| |
| <span class="comment">//Acquire exclusive lock</span> |
| <span class="identifier">mutex</span><span class="special">.</span><span class="identifier">lock</span><span class="special">();</span> |
| |
| <span class="comment">//Modify data</span> |
| |
| <span class="comment">//Atomically release exclusive lock and acquire sharable lock.</span> |
| <span class="comment">//More threads can acquire the sharable lock and read the data.</span> |
| <span class="identifier">mutex</span><span class="special">.</span><span class="identifier">unlock_and_lock_sharable</span><span class="special">();</span> |
| |
| <span class="comment">//Read data</span> |
| |
| <span class="comment">//Explicit unlocking</span> |
| <span class="identifier">mutex</span><span class="special">.</span><span class="identifier">unlock_sharable</span><span class="special">();</span> |
| </pre> |
| <p> |
| This can be simple, but in the presence of exceptions, it's complicated |
| to know what type of lock the mutex had when the exception was thrown and |
| what function we should call to unlock it: |
| </p> |
| <pre class="programlisting"><span class="keyword">try</span><span class="special">{</span> |
| <span class="comment">//Mutex operations</span> |
| <span class="special">}</span> |
| <span class="keyword">catch</span><span class="special">(...){</span> |
| <span class="comment">//What should we call? "unlock()" or "unlock_sharable()"</span> |
| <span class="comment">//Is the mutex locked?</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| We can use <span class="bold"><strong>lock transfer</strong></span> to simplify all |
| this management: |
| </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">interprocess_upgradable_mutex</span> <span class="identifier">mutex</span><span class="special">;</span> |
| |
| <span class="comment">//Acquire exclusive lock</span> |
| <span class="identifier">scoped_lock</span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">mutex</span><span class="special">);</span> |
| |
| <span class="comment">//Modify data</span> |
| |
| <span class="comment">//Atomically release exclusive lock and acquire sharable lock.</span> |
| <span class="comment">//More threads can acquire the sharable lock and read the data.</span> |
| <span class="identifier">sharable_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">s_lock</span><span class="special">));</span> |
| |
| <span class="comment">//Read data</span> |
| |
| <span class="comment">//The lock is automatically unlocked calling the appropriate unlock</span> |
| <span class="comment">//function even in the presence of exceptions.</span> |
| <span class="comment">//If the mutex was not locked, no function is called.</span> |
| </pre> |
| <p> |
| As we can see, even if an exception is thrown at any moment, the mutex |
| will be automatically unlocked calling the appropriate <code class="computeroutput"><span class="identifier">unlock</span><span class="special">()</span></code> or <code class="computeroutput"><span class="identifier">unlock_sharable</span><span class="special">()</span></code> method. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_summary"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_summary" title="Lock Transfer Summary">Lock |
| Transfer Summary</a> |
| </h4></div></div></div> |
| <div class="toc"><dl class="toc"> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_summary.lock_transfer_summary_scoped">Transfers |
| To Scoped Lock</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_summary.lock_transfer_summary_upgradable">Transfers |
| To Upgradable Lock</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_summary.lock_transfer_summary_sharable">Transfers |
| To Sharable Lock</a></span></dt> |
| </dl></div> |
| <p> |
| There are many lock transfer operations that we can classify according |
| to the operations presented in the upgradable mutex operations: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| <span class="bold"><strong>Guaranteed to succeed and non-blocking:</strong></span> |
| Any transition from a more restrictive lock to a less restrictive one. |
| Scoped -> Upgradable, Scoped -> Sharable, Upgradable -> Sharable. |
| </li> |
| <li class="listitem"> |
| <span class="bold"><strong>Not guaranteed to succeed:</strong></span> The operation |
| might succeed if no one has acquired the upgradable or exclusive lock: |
| Sharable -> Exclusive. This operation is a try operation. |
| </li> |
| <li class="listitem"> |
| <span class="bold"><strong>Guaranteed to succeed if using an infinite waiting:</strong></span> |
| Any transition that will succeed but needs to wait until all Sharable |
| locks are released: Upgradable -> Scoped. Since this is a blocking |
| operation, we can also choose not to wait infinitely and just try or |
| wait until a timeout is reached. |
| </li> |
| </ul></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_summary.lock_transfer_summary_scoped"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_summary.lock_transfer_summary_scoped" title="Transfers To Scoped Lock">Transfers |
| To Scoped Lock</a> |
| </h5></div></div></div> |
| <p> |
| Transfers to <code class="computeroutput"><span class="identifier">scoped_lock</span></code> |
| are guaranteed to succeed only from an <code class="computeroutput"><span class="identifier">upgradable_lock</span></code> |
| and only if a blocking operation is requested, due to the fact that this |
| operation needs to wait until all sharable locks are released. The user |
| can also use "try" or "timed" transfer to avoid infinite |
| locking, but succeed is not guaranteed. |
| </p> |
| <p> |
| A conversion from a <code class="computeroutput"><span class="identifier">sharable_lock</span></code> |
| is never guaranteed and thus, only a try operation is permitted: |
| </p> |
| <pre class="programlisting"><span class="comment">//Conversions to scoped_lock</span> |
| <span class="special">{</span> |
| <span class="identifier">upgradable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">u_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">);</span> |
| <span class="comment">//This calls unlock_upgradable_and_lock()</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">u_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| <span class="special">{</span> |
| <span class="identifier">upgradable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">u_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">);</span> |
| <span class="comment">//This calls try_unlock_upgradable_and_lock()</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">u_lock</span><span class="special">,</span> <span class="identifier">try_to_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| <span class="special">{</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">ptime</span> <span class="identifier">t</span> <span class="special">=</span> <span class="identifier">test</span><span class="special">::</span><span class="identifier">delay</span><span class="special">(</span><span class="number">100</span><span class="special">);</span> |
| <span class="identifier">upgradable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">u_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">);</span> |
| <span class="comment">//This calls timed_unlock_upgradable_and_lock()</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">u_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| <span class="special">{</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">);</span> |
| <span class="comment">//This calls try_unlock_sharable_and_lock()</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">s_lock</span><span class="special">,</span> <span class="identifier">try_to_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| </pre> |
| <div class="important"><table border="0" summary="Important"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../doc/src/images/important.png"></td> |
| <th align="left">Important</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">ptime</span></code> absolute time points used by |
| Boost.Interprocess synchronization mechanisms are UTC time points, |
| not local time points |
| </p></td></tr> |
| </table></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_summary.lock_transfer_summary_upgradable"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_summary.lock_transfer_summary_upgradable" title="Transfers To Upgradable Lock">Transfers |
| To Upgradable Lock</a> |
| </h5></div></div></div> |
| <p> |
| A transfer to an <code class="computeroutput"><span class="identifier">upgradable_lock</span></code> |
| is guaranteed to succeed only from a <code class="computeroutput"><span class="identifier">scoped_lock</span></code> |
| since scoped locking is a more restrictive locking than an upgradable |
| locking. This operation is also non-blocking. |
| </p> |
| <p> |
| A transfer from a <code class="computeroutput"><span class="identifier">sharable_lock</span></code> |
| is not guaranteed and only a "try" operation is permitted: |
| </p> |
| <pre class="programlisting"><span class="comment">//Conversions to upgradable</span> |
| <span class="special">{</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">);</span> |
| <span class="comment">//This calls try_unlock_sharable_and_lock_upgradable()</span> |
| <span class="identifier">upgradable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">u_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">s_lock</span><span class="special">,</span> <span class="identifier">try_to_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| <span class="special">{</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">);</span> |
| <span class="comment">//This calls unlock_and_lock_upgradable()</span> |
| <span class="identifier">upgradable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">u_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">e_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_summary.lock_transfer_summary_sharable"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_summary.lock_transfer_summary_sharable" title="Transfers To Sharable Lock">Transfers |
| To Sharable Lock</a> |
| </h5></div></div></div> |
| <p> |
| All transfers to a <code class="computeroutput"><span class="identifier">sharable_lock</span></code> |
| are guaranteed to succeed since both <code class="computeroutput"><span class="identifier">upgradable_lock</span></code> |
| and <code class="computeroutput"><span class="identifier">scoped_lock</span></code> are more |
| restrictive than <code class="computeroutput"><span class="identifier">sharable_lock</span></code>. |
| These operations are also non-blocking: |
| </p> |
| <pre class="programlisting"><span class="comment">//Conversions to sharable_lock</span> |
| <span class="special">{</span> |
| <span class="identifier">upgradable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">u_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">);</span> |
| <span class="comment">//This calls unlock_upgradable_and_lock_sharable()</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">u_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| <span class="special">{</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">);</span> |
| <span class="comment">//This calls unlock_and_lock_sharable()</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">e_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| </pre> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_not_locked"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_not_locked" title="Transferring Unlocked Locks">Transferring |
| Unlocked Locks</a> |
| </h4></div></div></div> |
| <p> |
| In the previous examples, the mutex used in the transfer operation was |
| previously locked: |
| </p> |
| <pre class="programlisting"> <span class="identifier">Mutex</span> <span class="identifier">mut</span><span class="special">;</span> |
| |
| <span class="comment">//This calls mut.lock()</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">);</span> |
| |
| <span class="comment">//This calls unlock_and_lock_sharable()</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">e_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| but it's possible to execute the transfer with an unlocked source, due |
| to explicit unlocking, a try, timed or a <code class="computeroutput"><span class="identifier">defer_lock</span></code> |
| constructor: |
| </p> |
| <pre class="programlisting"><span class="comment">//These operations can leave the mutex unlocked!</span> |
| |
| <span class="special">{</span> |
| <span class="comment">//Try might fail</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">,</span> <span class="identifier">try_to_lock</span><span class="special">);</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">e_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| <span class="special">{</span> |
| <span class="comment">//Timed operation might fail</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">,</span> <span class="identifier">time</span><span class="special">);</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">e_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| <span class="special">{</span> |
| <span class="comment">//Avoid mutex locking</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">,</span> <span class="identifier">defer_lock</span><span class="special">);</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">e_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| <span class="special">{</span> |
| <span class="comment">//Explicitly call unlock</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">);</span> |
| <span class="identifier">e_lock</span><span class="special">.</span><span class="identifier">unlock</span><span class="special">();</span> |
| <span class="comment">//Mutex was explicitly unlocked</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">e_lock</span><span class="special">));</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| If the source mutex was not locked: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| The target lock does not execute the atomic <code class="computeroutput"><span class="identifier">unlock_xxx_and_lock_xxx</span></code> |
| operation. |
| </li> |
| <li class="listitem"> |
| The target lock is also unlocked. |
| </li> |
| <li class="listitem"> |
| The source lock is released() and the ownership of the mutex is transferred |
| to the target. |
| </li> |
| </ul></div> |
| <pre class="programlisting"><span class="special">{</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">,</span> <span class="identifier">defer_lock</span><span class="special">);</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">e_lock</span><span class="special">));</span> |
| |
| <span class="comment">//Assertions</span> |
| <span class="identifier">assert</span><span class="special">(</span><span class="identifier">e_lock</span><span class="special">.</span><span class="identifier">mutex</span><span class="special">()</span> <span class="special">==</span> <span class="number">0</span><span class="special">);</span> |
| <span class="identifier">assert</span><span class="special">(</span><span class="identifier">s_lock</span><span class="special">.</span><span class="identifier">mutex</span><span class="special">()</span> <span class="special">!=</span> <span class="number">0</span><span class="special">);</span> |
| <span class="identifier">assert</span><span class="special">(</span><span class="identifier">e_lock</span><span class="special">.</span><span class="identifier">owns</span><span class="special">()</span> <span class="special">==</span> <span class="keyword">false</span><span class="special">);</span> |
| <span class="special">}</span> |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_failure"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.lock_conversions.lock_transfer_failure" title="Transfer Failures">Transfer |
| Failures</a> |
| </h4></div></div></div> |
| <p> |
| When executing a lock transfer, the operation can fail: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| The executed atomic mutex unlock plus lock function might throw. |
| </li> |
| <li class="listitem"> |
| The executed atomic function might be a "try" or "timed" |
| function that can fail. |
| </li> |
| </ul></div> |
| <p> |
| In the first case, the mutex ownership is not transferred and the source |
| lock's destructor will unlock the mutex: |
| </p> |
| <pre class="programlisting"><span class="special">{</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">,</span> <span class="identifier">defer_lock</span><span class="special">);</span> |
| |
| <span class="comment">//This operations throws because</span> |
| <span class="comment">//"unlock_and_lock_sharable()" throws!!!</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">e_lock</span><span class="special">));</span> |
| |
| <span class="comment">//Some code ...</span> |
| |
| <span class="comment">//e_lock's destructor will call "unlock()"</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| In the second case, if an internal "try" or "timed" |
| operation fails (returns "false") then the mutex ownership is |
| <span class="bold"><strong>not</strong></span> transferred, the source lock is unchanged |
| and the target lock's state will the same as a default construction: |
| </p> |
| <pre class="programlisting"><span class="special">{</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">s_lock</span><span class="special">(</span><span class="identifier">mut</span><span class="special">);</span> |
| |
| <span class="comment">//Internal "try_unlock_sharable_and_lock_upgradable()" returns false</span> |
| <span class="identifier">upgradable_lock</span><span class="special"><</span><span class="identifier">Mutex</span><span class="special">></span> <span class="identifier">u_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">s_lock</span><span class="special">,</span> <span class="identifier">try_to_lock</span><span class="special">));</span> |
| |
| <span class="identifier">assert</span><span class="special">(</span><span class="identifier">s_lock</span><span class="special">.</span><span class="identifier">mutex</span><span class="special">()</span> <span class="special">==</span> <span class="special">&</span><span class="identifier">mut</span><span class="special">);</span> |
| <span class="identifier">assert</span><span class="special">(</span><span class="identifier">s_lock</span><span class="special">.</span><span class="identifier">owns</span><span class="special">()</span> <span class="special">==</span> <span class="keyword">true</span><span class="special">);</span> |
| <span class="identifier">assert</span><span class="special">(</span><span class="identifier">u_lock</span><span class="special">.</span><span class="identifier">mutex</span><span class="special">()</span> <span class="special">==</span> <span class="number">0</span><span class="special">);</span> |
| <span class="identifier">assert</span><span class="special">(</span><span class="identifier">u_lock</span><span class="special">.</span><span class="identifier">owns</span><span class="special">()</span> <span class="special">==</span> <span class="keyword">false</span><span class="special">);</span> |
| |
| <span class="comment">//u_lock's destructor does nothing</span> |
| <span class="comment">//s_lock's destructor calls "unlock()"</span> |
| <span class="special">}</span> |
| </pre> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="interprocess.synchronization_mechanisms.file_lock"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock" title="File Locks">File |
| Locks</a> |
| </h3></div></div></div> |
| <div class="toc"><dl class="toc"> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock.file_lock_whats_a_file_lock">What's |
| A File Lock?</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock.file_lock_operations">File |
| Locking Operations</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock.file_lock_scoped_locks">Scoped |
| Lock and Sharable Lock With File Locking</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock.file_lock_not_thread_safe">Caution: |
| Synchronization limitations</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock.file_lock_careful_iostream">Be |
| Careful With Iostream Writing</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.file_lock.file_lock_whats_a_file_lock"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock.file_lock_whats_a_file_lock" title="What's A File Lock?">What's |
| A File Lock?</a> |
| </h4></div></div></div> |
| <p> |
| A file lock is an interprocess synchronization mechanism to protect concurrent |
| writes and reads to files using a mutex <span class="emphasis"><em>embedded</em></span> in |
| the file. This <span class="emphasis"><em>embedded mutex</em></span> has sharable and exclusive |
| locking capabilities. With a file lock, an existing file can be used as |
| a mutex without the need of creating additional synchronization objects |
| to control concurrent file reads or writes. |
| </p> |
| <p> |
| Generally speaking, we can have two file locking capabilities: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| <span class="bold"><strong>Advisory locking:</strong></span> The operating system |
| kernel maintains a list of files that have been locked. But does not |
| prevent writing to those files even if a process has acquired a sharable |
| lock or does not prevent reading from the file when a process has acquired |
| the exclusive lock. Any process can ignore an advisory lock. This means |
| that advisory locks are for <span class="bold"><strong>cooperating</strong></span> |
| processes, processes that can trust each other. This is similar to |
| a mutex protecting data in a shared memory segment: any process connected |
| to that memory can overwrite the data but <span class="bold"><strong>cooperative</strong></span> |
| processes use mutexes to protect the data first acquiring the mutex |
| lock. |
| </li> |
| <li class="listitem"> |
| <span class="bold"><strong>Mandatory locking:</strong></span> The OS kernel checks |
| every read and write request to verify that the operation can be performed |
| according to the acquired lock. Reads and writes block until the lock |
| is released. |
| </li> |
| </ul></div> |
| <p> |
| <span class="bold"><strong>Boost.Interprocess</strong></span> implements <span class="bold"><strong>advisory blocking</strong></span> because of portability reasons. |
| This means that every process accessing to a file concurrently, must cooperate |
| using file locks to synchronize the access. |
| </p> |
| <p> |
| In some systems file locking can be even further refined, leading to <span class="bold"><strong>record locking</strong></span>, where a user can specify a <span class="bold"><strong>byte range</strong></span> within the file where the lock is applied. |
| This allows concurrent write access by several processes if they need to |
| access a different byte range in the file. <span class="bold"><strong>Boost.Interprocess</strong></span> |
| does <span class="bold"><strong>not</strong></span> offer record locking for the |
| moment, but might offer it in the future. To use a file lock just include: |
| </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">sync</span><span class="special">/</span><span class="identifier">file_lock</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <p> |
| A file locking is a class that has <span class="bold"><strong>process lifetime</strong></span>. |
| This means that if a process holding a file lock ends or crashes, the operating |
| system will automatically unlock it. This feature is very useful in some |
| situations where we want to assure automatic unlocking even when the process |
| crashes and avoid leaving blocked resources in the system. A file lock |
| is constructed using the name of the file as an argument: |
| </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">sync</span><span class="special">/</span><span class="identifier">file_lock</span><span class="special">.</span><span class="identifier">hpp</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="comment">//This throws if the file does not exist or it can't</span> |
| <span class="comment">//open it with read-write access!</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">interprocess</span><span class="special">::</span><span class="identifier">file_lock</span> <span class="identifier">flock</span><span class="special">(</span><span class="string">"my_file"</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.file_lock.file_lock_operations"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock.file_lock_operations" title="File Locking Operations">File |
| Locking Operations</a> |
| </h4></div></div></div> |
| <p> |
| File locking has normal mutex operations plus sharable locking capabilities. |
| This means that we can have multiple readers holding the sharable lock |
| and writers holding the exclusive lock waiting until the readers end their |
| job. |
| </p> |
| <p> |
| However, file locking does <span class="bold"><strong>not</strong></span> support |
| upgradable locking or promotion or demotion (lock transfers), so it's more |
| limited than an upgradable lock. These are the operations: |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void lock()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to obtain |
| exclusive ownership of the file lock, and if another thread has exclusive |
| or sharable ownership of the mutex, it waits until it can obtain the ownership. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool try_lock()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to acquire |
| exclusive ownership of the file lock without waiting. If no other thread |
| has exclusive or sharable ownership of the file lock, this succeeds. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If it can acquire exclusive ownership |
| immediately returns true. If it has to wait, returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool timed_lock(const boost::posix_time::ptime |
| &abs_time)</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to acquire |
| exclusive ownership of the file lock waiting if necessary until no other |
| thread has exclusive or sharable ownership of the file lock or abs_time |
| is reached. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If acquires exclusive ownership, |
| returns true. Otherwise returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void unlock()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have exclusive |
| ownership of the file lock. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread releases the |
| exclusive ownership of the file lock. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void lock_sharable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to obtain |
| sharable ownership of the file lock, and if another thread has exclusive |
| ownership of the file lock, waits until it can obtain the ownership. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool try_lock_sharable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to acquire |
| sharable ownership of the file lock without waiting. If no other thread |
| has exclusive ownership of the file lock, this succeeds. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If it can acquire sharable ownership |
| immediately returns true. If it has to wait, returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>bool timed_lock_sharable(const boost::posix_time::ptime |
| &abs_time)</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread tries to acquire |
| sharable ownership of the file lock waiting if necessary until no other |
| thread has exclusive ownership of the file lock or abs_time is reached. |
| </p> |
| <p> |
| <span class="bold"><strong>Returns:</strong></span> If acquires sharable ownership, |
| returns true. Otherwise returns false. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> <span class="bold"><strong>interprocess_exception</strong></span> |
| on error. |
| </p> |
| <div class="sidebar"> |
| <div class="titlepage"></div> |
| <p> |
| <span class="emphasis"><em><span class="bold"><strong>void unlock_sharable()</strong></span></em></span> |
| </p> |
| </div> |
| <p> |
| <span class="bold"><strong>Precondition:</strong></span> The thread must have sharable |
| ownership of the file lock. |
| </p> |
| <p> |
| <span class="bold"><strong>Effects:</strong></span> The calling thread releases the |
| sharable ownership of the file lock. |
| </p> |
| <p> |
| <span class="bold"><strong>Throws:</strong></span> An exception derived from <span class="bold"><strong>interprocess_exception</strong></span> on error. |
| </p> |
| <p> |
| For more file locking methods, please <code class="computeroutput"><a class="link" href="../boost/interprocess/file_lock.html" title="Class file_lock">file_lock |
| reference</a></code>. |
| </p> |
| <div class="important"><table border="0" summary="Important"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../doc/src/images/important.png"></td> |
| <th align="left">Important</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">ptime</span></code> absolute time points used by |
| Boost.Interprocess synchronization mechanisms are UTC time points, not |
| local time points |
| </p></td></tr> |
| </table></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.file_lock.file_lock_scoped_locks"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock.file_lock_scoped_locks" title="Scoped Lock and Sharable Lock With File Locking">Scoped |
| Lock and Sharable Lock With File Locking</a> |
| </h4></div></div></div> |
| <p> |
| <code class="computeroutput"><a class="link" href="../boost/interprocess/scoped_lock.html" title="Class template scoped_lock">scoped_lock</a></code> |
| and <code class="computeroutput"><a class="link" href="../boost/interprocess/sharable_lock.html" title="Class template sharable_lock">sharable_lock</a></code> |
| can be used to make file locking easier in the presence of exceptions, |
| just like with mutexes: |
| </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">sync</span><span class="special">/</span><span class="identifier">file_lock</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">sync</span><span class="special">/</span><span class="identifier">sharable_lock</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="comment">//...</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="comment">//This process reads the file</span> |
| <span class="comment">// ...</span> |
| <span class="comment">//Open the file lock</span> |
| <span class="identifier">file_lock</span> <span class="identifier">f_lock</span><span class="special">(</span><span class="string">"my_file"</span><span class="special">);</span> |
| |
| <span class="special">{</span> |
| <span class="comment">//Construct a sharable lock with the filel lock.</span> |
| <span class="comment">//This will call "f_lock.sharable_lock()".</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">file_lock</span><span class="special">></span> <span class="identifier">sh_lock</span><span class="special">(</span><span class="identifier">f_lock</span><span class="special">);</span> |
| |
| <span class="comment">//Now read the file...</span> |
| |
| <span class="comment">//The sharable lock is automatically released by</span> |
| <span class="comment">//sh_lock's destructor</span> |
| <span class="special">}</span> |
| </pre> |
| <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">sync</span><span class="special">/</span><span class="identifier">file_lock</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">sync</span><span class="special">/</span><span class="identifier">scoped_lock</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| |
| <span class="comment">//...</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="comment">//This process writes the file</span> |
| <span class="comment">// ...</span> |
| <span class="comment">//Open the file lock</span> |
| <span class="identifier">file_lock</span> <span class="identifier">f_lock</span><span class="special">(</span><span class="string">"my_file"</span><span class="special">);</span> |
| |
| <span class="special">{</span> |
| <span class="comment">//Construct a sharable lock with the filel lock.</span> |
| <span class="comment">//This will call "f_lock.lock()".</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">file_lock</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">f_lock</span><span class="special">);</span> |
| |
| <span class="comment">//Now write the file...</span> |
| |
| <span class="comment">//The exclusive lock is automatically released by</span> |
| <span class="comment">//e_lock's destructor</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| However, lock transfers are only allowed between same type of locks, that |
| is, from a sharable lock to another sharable lock or from a scoped lock |
| to another scoped lock. A transfer from a scoped lock to a sharable lock |
| is not allowed, because <code class="computeroutput"><a class="link" href="../boost/interprocess/file_lock.html" title="Class file_lock">file_lock</a></code> |
| has no lock promotion or demotion functions like <code class="computeroutput"><span class="identifier">unlock_and_lock_sharable</span><span class="special">()</span></code>. This will produce a compilation error: |
| </p> |
| <pre class="programlisting"><span class="comment">//Open the file lock</span> |
| <span class="identifier">file_lock</span> <span class="identifier">f_lock</span><span class="special">(</span><span class="string">"my_file"</span><span class="special">);</span> |
| |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">file_lock</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">f_lock</span><span class="special">);</span> |
| |
| <span class="comment">//Compilation error, f_lock has no "unlock_and_lock_sharable()" member!</span> |
| <span class="identifier">sharable_lock</span><span class="special"><</span><span class="identifier">file_lock</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">f_lock</span><span class="special">));</span> |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.file_lock.file_lock_not_thread_safe"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock.file_lock_not_thread_safe" title="Caution: Synchronization limitations">Caution: |
| Synchronization limitations</a> |
| </h4></div></div></div> |
| <p> |
| If you plan to use file locks just like named mutexes, be careful, because |
| portable file locks have synchronization limitations, mainly because different |
| implementations (POSIX, Windows) offer different guarantees. Interprocess |
| file locks have the following limitations: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| It's unspecified if a <code class="computeroutput"><span class="identifier">file_lock</span></code> |
| synchronizes <span class="bold"><strong>two threads from the same process</strong></span>. |
| </li> |
| <li class="listitem"> |
| It's unspecified if a process can use two <code class="computeroutput"><span class="identifier">file_lock</span></code> |
| objects pointing to the same file. |
| </li> |
| </ul></div> |
| <p> |
| The first limitation comes mainly from POSIX, since a file handle is a |
| per-process attribute and not a per-thread attribute. This means that if |
| a thread uses a <code class="computeroutput"><span class="identifier">file_lock</span></code> |
| object to lock a file, other threads will see the file as locked. Windows |
| file locking mechanism, on the other hand, offer thread-synchronization |
| guarantees so a thread trying to lock the already locked file, would block. |
| </p> |
| <p> |
| The second limitation comes from the fact that file locking synchronization |
| state is tied with a single file descriptor in Windows. This means that |
| if two <code class="computeroutput"><span class="identifier">file_lock</span></code> objects |
| are created pointing to the same file, no synchronization is guaranteed. |
| In POSIX, when two file descriptors are used to lock a file if a descriptor |
| is closed, all file locks set by the calling process are cleared. |
| </p> |
| <p> |
| To sum up, if you plan to use portable file locking in your processes, |
| use the following restrictions: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| <span class="bold"><strong>For each file, use a single <code class="computeroutput"><span class="identifier">file_lock</span></code> |
| object per process.</strong></span> |
| </li> |
| <li class="listitem"> |
| <span class="bold"><strong>Use the same thread to lock and unlock a file.</strong></span> |
| </li> |
| <li class="listitem"> |
| If you are using a std::fstream/native file handle to write to the |
| file while using file locks on that file, <span class="bold"><strong>don't |
| close the file before releasing all the locks of the file.</strong></span> |
| </li> |
| </ul></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.file_lock.file_lock_careful_iostream"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock.file_lock_careful_iostream" title="Be Careful With Iostream Writing">Be |
| Careful With Iostream Writing</a> |
| </h4></div></div></div> |
| <p> |
| As we've seen file locking can be useful to synchronize two processes, |
| but <span class="bold"><strong>make sure data is written to the file</strong></span> |
| before unlocking the file lock. Take in care that iostream classes do some |
| kind of buffering, so if you want to make sure that other processes can |
| see the data you've written, you have the following alternatives: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| Use native file functions (read()/write() in Unix systems and ReadFile/WriteFile |
| in Windows systems) instead of iostream. |
| </li> |
| <li class="listitem"> |
| Flush data before unlocking the file lock in writers using <code class="computeroutput"><span class="identifier">fflush</span></code> if you are using standard |
| C functions or the <code class="computeroutput"><span class="identifier">flush</span><span class="special">()</span></code> member function when using C++ iostreams. |
| In windows you can't even use another class to access the same file. |
| </li> |
| </ul></div> |
| <pre class="programlisting"><span class="comment">//...</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="comment">//This process writes the file</span> |
| <span class="comment">// ...</span> |
| <span class="comment">//Open the file lock</span> |
| <span class="identifier">fstream</span> <span class="identifier">file</span><span class="special">(</span><span class="string">"my_file"</span><span class="special">)</span> |
| <span class="identifier">file_lock</span> <span class="identifier">f_lock</span><span class="special">(</span><span class="string">"my_lock_file"</span><span class="special">);</span> |
| |
| <span class="special">{</span> |
| <span class="identifier">scoped_lock</span><span class="special"><</span><span class="identifier">file_lock</span><span class="special">></span> <span class="identifier">e_lock</span><span class="special">(</span><span class="identifier">f_lock</span><span class="special">);</span> |
| |
| <span class="comment">//Now write the file...</span> |
| |
| <span class="comment">//Flush data before unlocking the exclusive lock</span> |
| <span class="identifier">file</span><span class="special">.</span><span class="identifier">flush</span><span class="special">();</span> |
| <span class="special">}</span> |
| </pre> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="interprocess.synchronization_mechanisms.message_queue"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.message_queue" title="Message Queue">Message |
| Queue</a> |
| </h3></div></div></div> |
| <div class="toc"><dl class="toc"> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.message_queue.message_queue_whats_a_mq">What's |
| A Message Queue?</a></span></dt> |
| <dt><span class="section"><a href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.message_queue.message_queue_example">Using |
| a message queue</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.message_queue.message_queue_whats_a_mq"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.message_queue.message_queue_whats_a_mq" title="What's A Message Queue?">What's |
| A Message Queue?</a> |
| </h4></div></div></div> |
| <p> |
| A message queue is similar to a list of messages. Threads can put messages |
| in the queue and they can also remove messages from the queue. Each message |
| can have also a <span class="bold"><strong>priority</strong></span> so that higher |
| priority messages are read before lower priority messages. Each message |
| has some attributes: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| A priority. |
| </li> |
| <li class="listitem"> |
| The length of the message. |
| </li> |
| <li class="listitem"> |
| The data (if length is bigger than 0). |
| </li> |
| </ul></div> |
| <p> |
| A thread can send a message to or receive a message from the message queue |
| using 3 methods: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> |
| <li class="listitem"> |
| <span class="bold"><strong>Blocking</strong></span>: If the message queue is |
| full when sending or the message queue is empty when receiving, the |
| thread is blocked until there is room for a new message or there is |
| a new message. |
| </li> |
| <li class="listitem"> |
| <span class="bold"><strong>Try</strong></span>: If the message queue is full |
| when sending or the message queue is empty when receiving, the thread |
| returns immediately with an error. |
| </li> |
| <li class="listitem"> |
| <span class="bold"><strong>Timed</strong></span>: If the message queue is full |
| when sending or the message queue is empty when receiving, the thread |
| retries the operation until succeeds (returning successful state) or |
| a timeout is reached (returning a failure). |
| </li> |
| </ul></div> |
| <p> |
| A message queue <span class="bold"><strong>just copies raw bytes between processes</strong></span> |
| and does not send objects. This means that if we want to send an object |
| using a message queue <span class="bold"><strong>the object must be binary serializable</strong></span>. |
| For example, we can send integers between processes but <span class="bold"><strong>not</strong></span> |
| a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span></code>. You should use <span class="bold"><strong>Boost.Serialization</strong></span> |
| or use advanced <span class="bold"><strong>Boost.Interprocess</strong></span> mechanisms |
| to send complex data between processes. |
| </p> |
| <p> |
| The <span class="bold"><strong>Boost.Interprocess</strong></span> message queue is |
| a named interprocess communication: the message queue is created with a |
| name and it's opened with a name, just like a file. When creating a message |
| queue, the user must specify the maximum message size and the maximum message |
| number that the message queue can store. These parameters will define the |
| resources (for example the size of the shared memory used to implement |
| the message queue if shared memory is used). |
| </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="comment">//Create a message_queue. If the queue</span> |
| <span class="comment">//exists throws an exception</span> |
| <span class="identifier">message_queue</span> <span class="identifier">mq</span> |
| <span class="special">(</span><span class="identifier">create_only</span> <span class="comment">//only create</span> |
| <span class="special">,</span><span class="string">"message_queue"</span> <span class="comment">//name</span> |
| <span class="special">,</span><span class="number">100</span> <span class="comment">//max message number</span> |
| <span class="special">,</span><span class="number">100</span> <span class="comment">//max message size</span> |
| <span class="special">);</span> |
| </pre> |
| <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="comment">//Creates or opens a message_queue. If the queue</span> |
| <span class="comment">//does not exist creates it, otherwise opens it.</span> |
| <span class="comment">//Message number and size are ignored if the queue</span> |
| <span class="comment">//is opened</span> |
| <span class="identifier">message_queue</span> <span class="identifier">mq</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">"message_queue"</span> <span class="comment">//name</span> |
| <span class="special">,</span><span class="number">100</span> <span class="comment">//max message number</span> |
| <span class="special">,</span><span class="number">100</span> <span class="comment">//max message size</span> |
| <span class="special">);</span> |
| </pre> |
| <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="comment">//Opens a message_queue. If the queue</span> |
| <span class="comment">//does not exist throws an exception.</span> |
| <span class="identifier">message_queue</span> <span class="identifier">mq</span> |
| <span class="special">(</span><span class="identifier">open_only</span> <span class="comment">//only open</span> |
| <span class="special">,</span><span class="string">"message_queue"</span> <span class="comment">//name</span> |
| <span class="special">);</span> |
| </pre> |
| <p> |
| The message queue is explicitly removed calling the static <code class="computeroutput"><span class="identifier">remove</span></code> function: |
| </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">message_queue</span><span class="special">::</span><span class="identifier">remove</span><span class="special">(</span><span class="string">"message_queue"</span><span class="special">);</span> |
| </pre> |
| <p> |
| The function can fail if the message queue is still being used by any process. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="interprocess.synchronization_mechanisms.message_queue.message_queue_example"></a><a class="link" href="synchronization_mechanisms.html#interprocess.synchronization_mechanisms.message_queue.message_queue_example" title="Using a message queue">Using |
| a message queue</a> |
| </h4></div></div></div> |
| <p> |
| To use a message queue you must 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">ipc</span><span class="special">/</span><span class="identifier">message_queue</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| </pre> |
| <p> |
| In the following example, the first process creates the message queue, |
| and writes an array of integers on it. The other process just reads the |
| array and checks that the sequence number is correct. This is the first |
| 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">ipc</span><span class="special">/</span><span class="identifier">message_queue</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">vector</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">int</span> <span class="identifier">main</span> <span class="special">()</span> |
| <span class="special">{</span> |
| <span class="keyword">try</span><span class="special">{</span> |
| <span class="comment">//Erase previous message queue</span> |
| <span class="identifier">message_queue</span><span class="special">::</span><span class="identifier">remove</span><span class="special">(</span><span class="string">"message_queue"</span><span class="special">);</span> |
| |
| <span class="comment">//Create a message_queue.</span> |
| <span class="identifier">message_queue</span> <span class="identifier">mq</span> |
| <span class="special">(</span><span class="identifier">create_only</span> <span class="comment">//only create</span> |
| <span class="special">,</span><span class="string">"message_queue"</span> <span class="comment">//name</span> |
| <span class="special">,</span><span class="number">100</span> <span class="comment">//max message number</span> |
| <span class="special">,</span><span class="keyword">sizeof</span><span class="special">(</span><span class="keyword">int</span><span class="special">)</span> <span class="comment">//max message size</span> |
| <span class="special">);</span> |
| |
| <span class="comment">//Send 100 numbers</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="keyword">int</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="number">100</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">){</span> |
| <span class="identifier">mq</span><span class="special">.</span><span class="identifier">send</span><span class="special">(&</span><span class="identifier">i</span><span class="special">,</span> <span class="keyword">sizeof</span><span class="special">(</span><span class="identifier">i</span><span class="special">),</span> <span class="number">0</span><span class="special">);</span> |
| <span class="special">}</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> |
| This is the second 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">ipc</span><span class="special">/</span><span class="identifier">message_queue</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">vector</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">int</span> <span class="identifier">main</span> <span class="special">()</span> |
| <span class="special">{</span> |
| <span class="keyword">try</span><span class="special">{</span> |
| <span class="comment">//Open a message queue.</span> |
| <span class="identifier">message_queue</span> <span class="identifier">mq</span> |
| <span class="special">(</span><span class="identifier">open_only</span> <span class="comment">//only create</span> |
| <span class="special">,</span><span class="string">"message_queue"</span> <span class="comment">//name</span> |
| <span class="special">);</span> |
| |
| <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">priority</span><span class="special">;</span> |
| <span class="identifier">message_queue</span><span class="special">::</span><span class="identifier">size_type</span> <span class="identifier">recvd_size</span><span class="special">;</span> |
| |
| <span class="comment">//Receive 100 numbers</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="keyword">int</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="number">100</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">){</span> |
| <span class="keyword">int</span> <span class="identifier">number</span><span class="special">;</span> |
| <span class="identifier">mq</span><span class="special">.</span><span class="identifier">receive</span><span class="special">(&</span><span class="identifier">number</span><span class="special">,</span> <span class="keyword">sizeof</span><span class="special">(</span><span class="identifier">number</span><span class="special">),</span> <span class="identifier">recvd_size</span><span class="special">,</span> <span class="identifier">priority</span><span class="special">);</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">number</span> <span class="special">!=</span> <span class="identifier">i</span> <span class="special">||</span> <span class="identifier">recvd_size</span> <span class="special">!=</span> <span class="keyword">sizeof</span><span class="special">(</span><span class="identifier">number</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="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">message_queue</span><span class="special">::</span><span class="identifier">remove</span><span class="special">(</span><span class="string">"message_queue"</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="identifier">message_queue</span><span class="special">::</span><span class="identifier">remove</span><span class="special">(</span><span class="string">"message_queue"</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> |
| To know more about this class and all its operations, please see the <code class="computeroutput"><a class="link" href="../boost/interprocess/message_queue.html" title="Type definition message_queue">message_queue</a></code> class |
| reference. |
| </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-2012 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="offset_ptr.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="managed_memory_segments.html"><img src="../../../doc/src/images/next.png" alt="Next"></a> |
| </div> |
| </body> |
| </html> |