    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: Applied Reading - Taming Shared Memory</title>
        <link>https://members.accu.org/index.php/journals/376</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>


        <h2>Journal Articles</h2>


<div class="xar-mod-head"><span class="xar-mod-title">Overload Journal #51 - Oct 2002 + Programming Topics</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/journals/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c78/">Overload</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c194/">51</a>
                    (8)
<br />

                                            <a href="https://members.accu.org/index.php/journals/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c65/">Programming</a>
                    (877)
<br />

                                            <a href="https://members.accu.org/index.php/journals/c194-65/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/journals/c194+65/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;Applied Reading - Taming Shared Memory</h1>
<p><strong>Author:</strong>&nbsp;</p>
<p>
<strong>Date:</strong> 02 August 2002 22:58:12 +01:00 or Fri, 02 August 2002 22:58:12 +01:00</p>
<p><strong>Summary:</strong>&nbsp;</p>
<p><strong>Body:</strong>&nbsp;<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e18" id="d0e18"></a></h2>
</div>
<p>I consider myself something of a connoisseur of technical books.
I pride myself on my small but expanding collection. Of course, an
important part of maintaining a useful book collection is knowing
what information your books contain, so you can find it when you
need it. Though I often forget the details of a solution I read
about, I remember where I saw it, and what the original problem
was. My purpose in writing this piece is two-fold: to show you how
I solved a particular problem, and to point you at the books I used
along the way.</p>
<p>When I was given this task, some of the solution was already
defined. There was an existing architecture with a client and
server sending messages over TCP/IP. A requirement had arisen for
an additional client interface for CGI processes. Since each CGI
process is short-lived, creating a new socket connection in each
process would be too expensive. So the idea was to route messages
through a daemon that maintains a persistent connection to the
server. Because the daemon can be located on the same Unix box as
the CGI processes, the two can use an Interprocess Communication
(IPC) mechanism with less overhead than sockets. This is where I
started working from.</p>
<p>The first decision was to choose the exact IPC mechanism to use.
Unix has several, including pipes, fifos, sockets, message queues,
and shared memory. I ruled out pipes because they require a
parent-child relationship between processes, which I did not have.
Fifos, like pipes, are best suited for one-to-one communication,
whereas I needed manyto- one. I had heard that message queues were
unnecessarily complex and grandiose, so I was hesitant to use them.
Shared memory, on the other hand, is basically a free-form medium,
and I was pretty confident that it would be fast enough, so I
started the implementation based on shared memory.<sup>[<a name=
"d0e26" href="#ftn.d0e26" id="d0e26">1</a>]</sup> I'll walk you
through the basics of my solution below.</p>
<p>Shared memory is what the name implies; it is a portion of
address space that is shared between processes. Normally each
process has its own address space, which is entirely separate from
those of other processes. The operating system uses hardware to map
a process's virtual address space onto physical memory. This
ensures that no process can access memory in another process's
address space; so no process can disturb the integrity of another.
Shared memory is an exception to this system. When two processes
attach the same shared memory segment, they are telling the
operating system to relax the normal restrictions by mapping a
portion of their address space onto the same memory.</p>
<p>The definitive book on Unix IPC is &quot;UNIX Network Programming&quot; by
the late Richard Stevens [<a href="#Stevens">Stevens</a>]. Anyone
doing heavy Unix should be familiar with it. After consulting this
authority, we see that getting access to shared memory is a
two-step process. First, a shared memory identifier is obtained,
using the shmget() system call. The segment is identified by an
integer key, and has a set of permissions controlling which
processes may read, write, or execute it, much like a Unix file.
The <tt class="literal">IPC_CREAT</tt> and <tt class=
"literal">IPC_EXCL</tt> flags control creation of the segment if it
doesn't exist. Once a segment is created, it is available for use
by any process with appropriate permissions. After obtaining a
segment identifier, a process must attach the segment into its
address space using the <tt class="literal">shmat()</tt> call. The
return from <tt class="literal">shmat()</tt> is the base address
where the segment was attached, i.e., the address of the first byte
located in the segment. The memory is now available for use just
like any other memory in the process's address space. Here's an
example:</p>
<pre class="programlisting">
  #include &lt;sys/shm.h&gt;

  int main() {
      int id = shmget(0x1000 /*key*/,
                      sizeof(int) /*size*/,
                      0600 | IPC_CREAT /*creation flags*/);
      void* base = shmat(id /*identifier*/,
                         0 /*base address*/, 0 /*flags*/);
      *reinterpret_cast&lt;int*&gt;(base) = 42;
}
</pre>
<p>After the call to <tt class="literal">shmat()</tt> above, the
process's address space might look as shown in Figure 1 below.</p>
<div class="figure"><a name="d0e56" id="d0e56"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/shm_figure0.gif"
align="middle" alt="Address space after call to shmat()"></div>
<p class="title c3">Figure 1. Address space after call to
shmat()</p>
</div>
<p>The low-level C interface of <tt class=
"literal">shmget()</tt><sup>[<a name="d0e66" href="#ftn.d0e66" id=
"d0e66">2</a>]</sup> and <tt class="literal">shmat()</tt>, with
their untyped integer handles and bit flags are just what you get
with Unix system calls. Now I have great respect for Unix and C,
but sometimes I want an interface with a little more
structure...err...I mean class. So we'll wrap up some of the
error-prone details in a C++ interface. Our first step in building
a set of C++ classes to handle shared memory will be to encapsulate
a shared memory segment:</p>
<pre class="programlisting">
  class shm_segment {

  public:
      enum CreationMode { NoCreate, CreateOk, MustCreate, CreateOwned };
      shm_segment(int key, CreationMode mode, int size=0, int perm=0600);
      ~shm_segment();
      void* get_base() const;
      unsigned long get_size() const;
      void destroy();

  private:
      int key_;
      int id_;
      void* base_;
      unsigned long size_;
      bool owner_;
  };

  class shm_create_exception: public std::exception {
  public:
      const char* what() const throw() {
          return &quot;error creating shared memory segment&quot;;
      }
};
</pre>
<div class="figure"><a name="d0e75" id="d0e75"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/shm_figure1.gif"
align="middle" alt="Allocating memory"></div>
<p class="title c3">Figure 2. Allocating memory</p>
</div>
<p>This class simply wraps creation and destruction of a shared
memory segment. The <tt class="literal">CreationMode</tt> argument
determines whether the segment will be created if it doesn't exist.
This corresponds to the meaningful combinations of the <tt class=
"literal">IPC_CREAT</tt> and <tt class="literal">IPC_EXCL</tt>
flags. The <tt class="literal">CreateOwned</tt> option sets our
<tt class="literal">owner_flag</tt>, which we'll use to determine
if the shared memory segment should be removed when the <tt class=
"literal">shm_segment</tt> object is destroyed. It might be
possible to store a reference count and remove the segment only
after all processes are finished with it, but it's probably best to
have a clear ownership policy instead. The implementation of
<tt class="literal">shm_segment</tt> is straight forward.</p>
<p>The <tt class="literal">shm_segment</tt> class makes it a little
easier to get a segment, but once it is created, there is still no
internal structure to the segment; it's just a raw chunk of memory.
In order to add more structure, we will need a way to store
pointers inside the segment. But this poses a problem. Since each
process may attach the segment at a different base address, a
pointer into the segment created by one process may not be valid in
another process; it may point somewhere else entirely. To solve
this problem, we will store offsets from the base instead of raw
pointers. We'll create a simple pointer class for this purpose:</p>
<pre class="programlisting">
  template&lt;typename T&gt;
  class shm_ptr {
  public:
      shm_ptr();
      shm_ptr(T* rawptr, const shm_segment&amp; seg);
      // compiler generated copy constructor and
      // assignment are ok
      T* get(const shm_segment&amp; seg) const;
      void reset(T* rawptr, const shm_segment&amp; seg);
  private:
      long offset_;
  };

  class shm_ptr_out_of_bounds: public std::exception {
  public:
      const char* what() const throw() {
          return &quot;shm_ptr cannot be created with address outside of segment&quot;;
      }
  };
</pre>
<p>Notice that the only data member is an integer representing the
offset in bytes from the base address. This offset will have the
same meaning for all the processes using our shared memory segment,
so it can safely be stored in shared memory. Notice also that our
interface requires the user to pass the <tt class=
"literal">shm_segment</tt> when accessing the pointer. This is
somewhat cumbersome, but it yields a general design where each
process may attach multiple shared memory segments. Alternatively,
shm_segment could be a singleton, which would make it easier for
shm_ptr to provide the usual indirection operators, but I found
this unnecessary.</p>
<p>Our <tt class="literal">shm_ptr</tt> gives us a safe way to
store a pointer in shared memory, but we don't yet have a way to
create that pointer. It would be possible to choose arbitrary
locations for data and manually place it there with some pointer
arithmetic, e.g.,</p>
<pre class="programlisting">
  shm_ptr&lt;char&gt; buffer(reinterpret_cast&lt;char*&gt;(mysegment.getBase()), mysegment);
  shm_ptr&lt;char&gt; buffer2(reinterpret_cast&lt;char*&gt;(mysegment.getBase())+1000, mysegment);
</pre>
<p>but I think we can all agree that this is too ugly and
inflexible. What we really need is a way to allocate objects in
shared memory with the ease of ordinary operators new and delete.
To accomplish this, we'll write a shared memory allocator
class:</p>
<pre class="programlisting">
  struct shm_allocator_header;

  class shm_allocator {

  public:
      explicit shm_allocator(const shm_segment&amp; seg);
      void* alloc(size_t nbytes);
      void free(void* addr);
      void* get_root_object() const;
      void set_root_object(void* obj);
      const shm_segment&amp; get_segment() const;

  private:
      const shm_segment&amp; seg_;
      shm_allocator_header* header_;
  };
</pre>
<p>The interface provides <tt class="literal">alloc()</tt> and
<tt class="literal">free()</tt> methods, as well as methods to get
and set a &quot;root object.&quot; The root object gives us a fixed access
point for processes to share objects. There is also a <tt class=
"literal">get_segment()</tt> method to find out what shared memory
segment an allocator is using.</p>
<p>When I was writing my first implementation, and I knew I needed
an allocator, I remembered seeing one somewhere, and after flipping
through a few pages, I found Chapter 4 in &quot;Modern C++ Design,&quot;
which describes small object allocations [<a href=
"#Alexandrescu">Alexandrescu</a>].<sup>[<a name="d0e143" href=
"#ftn.d0e143" id="d0e143">3</a>]</sup>An example there gave me
enough information to sketch out my initial implementation. The
basic idea of an allocator is to store a control block in the
memory preceding the address returned to the user. This example
used:</p>
<pre class="programlisting">
  struct MemControlBlock {
      bool available_;
      MemControlBlock* prev;
      MemControlBlock* next;
  }
</pre>
<p>Starting from a root block, you just walk down the list of
blocks looking for one that's free and big enough for the requested
allocation. The layout of memory looks as shown in Figure 2
above.</p>
<p>Incidentally, Alexandrescu mentions the many tradeoffs
associated with memory allocators, and points us to Knuth's
masterpiece for more details [<a href="#Knuth">Knuth</a>]. For some
variety, I decided to base our implementation on a section in &quot;The
C Programming Language&quot; on implementing malloc() and free(); it is
a little simpler to explain, and it gives me an opportunity to
recognize a classic (and still relevant) book [<a href=
"#KandR">KandR</a>]. The idea for the allocator is the same, but
the details have changed. Each block now stores its size and a
pointer to the next block.</p>
<pre class="programlisting">
<tt class="literal"> struct shm_allocator_block {
      shm_ptr&lt;shm_allocator_block&gt; next;
      size_t size;
   };</tt>
</pre>
<p>A header block stores a pointer to the beginning of a linked
list of free blocks:</p>
<pre class="programlisting">
  struct shm_allocator_header {
      shm_ptr&lt;void&gt; rootobj;
      pthread_mutex_t lock;
      shm_ptr&lt;shm_allocator_block&gt; freelist;
  };
</pre>
<p>The free list is a singly-linked circular list of blocks not
currently in use. The list is linked in order of ascending
addresses to make it easy to combine adjacent free blocks. Here is
the implementation of alloc().</p>
<pre class="programlisting">
  void* shm_allocator::alloc(size_t nbytes) {
      scoped_lock guard(&amp;header_-&gt;lock);
      size_t nunits = (nbytes + sizeof(shm_allocator_block) - 1) /
               sizeof(shm_allocator_block) + 1;
      shm_allocator_block* prev = header_-&gt;freelist.get(seg_);
      shm_allocator_block* block = prev-&gt;next.get(seg_);
      do {
          if (block-&gt;size &gt;= nunits) {
              if (block-&gt;size == nunits)
                  prev-&gt;next = block-&gt;next;
              else {
                  block-&gt;size -= nunits;
                  block += block-&gt;size;
                  block-&gt;size = nunits;
              }
              header_-&gt;freelist.reset(prev, seg_);
              return (void*)(block+1);
          }
          prev = block;
          block = block-&gt;next.get(seg_);
      } while(block != header_-&gt;freelist.get(seg_));
      return NULL;
  }
</pre>
<p>The code above walks the free list looking for a block big
enough to hold the requested number of bytes. If the block it finds
is larger than needed, it splits it in two. Otherwise it returns it
as is. If no block is found, it returns null. Size calculations are
made in units equal to the size of one <tt class=
"literal">shm_allocator_block</tt>. This makes the pointer
arithmetic a little simpler, and ensures that all memory allocated
will have the same alignment as shm_allocator_block.</p>
<p>The implementation of <tt class="literal">free()</tt> is shown
below:</p>
<pre class="programlisting">
  void shm_allocator::free(void* addr) {
      scoped_lock guard(&amp;header_-&gt;lock);
      shm_allocator_block* block = static_cast&lt;shm_allocator_block*&gt;(addr) - 1;
      shm_allocator_block* pos = header_-&gt;freelist.get(seg_);
      while (block &gt; pos &amp;&amp; block &lt; pos-&gt;next.get(seg_)) {
          if (pos &gt;= pos-&gt;next.get(seg_) &amp;&amp; (block &gt; pos || block &lt; pos-&gt;next.get(seg_)))
              break;
          pos = pos-&gt;next.get(seg_);
      }
      //try to combine with upper block
      if (block + block-&gt;size == pos-&gt;next.get(seg_)) {
          block-&gt;size += pos-&gt;next.get(seg_)-&gt;size;
          block-&gt;next = pos-&gt;next.get(seg_)-&gt;next;
      }
      else
          block-&gt;next = pos-&gt;next;
      //try to combine with lower block
      if (pos + pos-&gt;size == block) {
          pos-&gt;size += block-&gt;size;
          pos-&gt;next = block-&gt;next;
      }
      else
          pos-&gt;next.reset(block, seg_);
      header_-&gt;freelist.reset(pos, seg_);
  }
</pre>
<p>The block is inserted into its correct spot in the free list
(remember the list is sorted by address). Then we check for
adjacent free blocks. If any are found, we combine them with the
current block by just forgetting that the upper block exists and
increasing the size of the lower block. So, after a few allocations
and deallocations, memory might look as shown in Figure 3
below.</p>
<div class="figure"><a name="d0e187" id="d0e187"></a>
<div class="mediaobject c2"><img src="/var/uploads/journals/resources/shm_figure2.gif"
align="middle" alt=
"Memory after allocations and deallocations"></div>
<p class="title c3">Figure 3. Memory after allocations and
deallocations</p>
</div>
<p>We'll also overload operators new and delete to work with
<tt class="literal">shm_allocator</tt>. The basic details for doing
this, and some pitfalls can be found in Item 36 of &quot;Exceptional
C++&quot; [<a href="#Sutter">Sutter</a>].</p>
<pre class="programlisting">
  void* operator new(size_t s, shm_allocator&amp; a) {
      return a.alloc(s);
  }

  void operator delete(void* p, shm_allocator&amp; a) {
      a.free(p);
  }
</pre>
<p>We can overload <tt class="literal">new[]</tt> and <tt class=
"literal">delete[]</tt> similarly. The proper syntax for calling
overloaded operator new or delete may be mysterious to you.
Assuming we have already defined a class Message, we can create a
new Message object in shared memory using:</p>
<pre class="programlisting">
  Message* m = new (a) Message;
      // a is a shm_allocator
</pre>
<p>The above is a new expression which calls our overloaded
<tt class="literal">operator new</tt>, followed by the Message
constructor. Destroying the Message object is not quite as
simple:</p>
<pre class="programlisting">
  m-&gt;~Message();
  operator delete(m, a);
</pre>
<p>We must first make an explicit call to the destructor and then
deallocate the memory. Two steps are required because there is no
way to form a delete expression which calls an overloaded operator
delete. You'll notice that the lines above are equivalent to
these:</p>
<pre class="programlisting">
  m-&gt;~Message();
  a.free(m);
</pre>
<p>So, one might be tempted to overload only operator new; however,
it is very important that we overload operator delete as well,
because if the Message constructor throws an exception our
overloaded <tt class="literal">operator delete</tt> will be
automatically called. If there was no <tt class="literal">operator
delete</tt> to match the operator new used to allocate the memory,
bad things would happen.</p>
<p>We now have a general purpose allocator that we can use to help
us build arbitrary structures in shared memory. To demonstrate its
use, we'll write our final class, a producer-consumer queue in
shared memory:</p>
<pre class="programlisting">
  template&lt;typename T&gt; struct shm_queue_header;

  template&lt;typename T&gt;
  class shm_queue {

  public:
      shm_queue(shm_allocator&amp; a, size_t maxsize);
      ~shm_queue();
      void push(shm_ptr&lt;T&gt; obj);
      shm_ptr&lt;T&gt; pop();
      size_t size() const;

  private:
      const size_t MaxQueueSize;
      shm_queue_header&lt;T&gt;* header_;
      shm_allocator&amp; a_;
      const shm_segment&amp; seg_;

      // disallowed (not implemented)
      shm_queue(const shm_queue&amp; copy);
      shm_queue&amp; operator=(constshm_queue&amp; rhs);
};
</pre>
<p>This is a basic queue, with simple push() and <tt class=
"literal">pop()</tt> methods.<sup>[<a name="d0e241" href=
"#ftn.d0e241" id="d0e241">4</a>]</sup>The queue is created with a
<tt class="literal">shm_allocator</tt>, which it then uses to
allocate nodes. A maximum size is also specified to ensure that the
producer(s) don't get too far ahead of the consumer(s). The
implementation is a singly-linked list.</p>
<pre class="programlisting">
  template&lt;typename T&gt;
  struct shm_queue_node {
      shm_ptr&lt;T&gt; data;
      shm_ptr&lt;shm_queue_node&gt; next;
  };

  template&lt;typename T&gt;
  struct shm_queue_header {
      size_t size;
      shm_ptr&lt;shm_queue_node&lt;T&gt; &gt; head;
      shm_ptr&lt;shm_queue_node&lt;T&gt; &gt; tail;
      pthread_mutex_t lock;
      pthread_cond_t ready_for_push;
      pthread_cond_t ready_for_pop;
  };
</pre>
<p>Now, those <tt class="literal">pthread_xxx</tt> members give me
a chance to make my final recommendation: &quot;Programming with POSIX
Threads&quot; by David Butenhof [<a href="#Butenhof">Butenhof</a>]. This
is an excellent introduction to threaded programming, and
specifically, Pthreads. &quot;But wait a minute!&quot; you say, &quot;When did we
introduce threads into the picture?&quot; Well, the primitives needed to
synchronize two threads (which inherently share memory) are very
similar to those needed to synchronize processes using Unix shared
memory. They are so similar, in fact, that Pthreads provides a way
to use mutexes and condition variables in this scenario. If your
system defines the <tt class=
"literal">_POSIX_THREAD_PROCESS_SHARED</tt> macro, you can place
Pthread objects in shared memory if you set the <tt class=
"literal">pthread_process_shared</tt> attribute. This works on the
Solaris system I tested on, but is not supported on my Linux
system.<sup>[<a name="d0e279" href="#ftn.d0e279" id=
"d0e279">5</a>]</sup></p>
<p>For a little more demonstration of Pthreads, here's the
implementation of our <tt class="literal">scoped_lock</tt>
class:</p>
<pre class="programlisting">
  #include &lt;pthread.h&gt;
  
  class scoped_lock {

  public:

      scoped_lock(pthread_mutex_t* mutex) {
          mutex_ = mutex;
          pthread_mutex_lock(mutex_);
      }

      ~scoped_lock() {
          pthread_mutex_unlock(mutex_);
      }

      void wait(pthread_cond_t* cond) {
          pthread_cond_wait(cond, mutex_);
      }

  private:
      pthread_mutex_t* mutex_;
      scoped_lock(const scoped_lock&amp; copy);
      scoped_lock&amp; operator=(const scoped_lock&amp; rhs);
  };
</pre>
<p>And, using <tt class="literal">scoped_lock</tt> , the
implementation of <tt class="literal">shm_queue::push()</tt>:</p>
<pre class="programlisting">
  template&lt;typename T&gt;
  void shm_queue&lt;T&gt;::push(shm_ptr&lt;T&gt; obj) {
      scoped_lock guard(&amp;header_-&gt;lock);
      while (header_-&gt;size &gt; MaxQueueSize) {
          guard.wait(&amp;header_-&gt;ready_for_push);
      }
      shm_queue_node&lt;T&gt;* node = new (a_) shm_queue_node&lt;T&gt;;
      node-&gt;data = obj;
      node-&gt;next.reset(0, seg_);
      if (header_-&gt;head.get(seg_) != 0) {
          header_-&gt;head.get(seg_)-&gt;next.reset(node, seg_);
      }
      else {
          header_-&gt;tail.reset(node, seg_);
      }
      header_-&gt;head.reset(node, seg_);
      ++header_-&gt;size;
      pthread_cond_signal(&amp;header_-&gt;ready_for_pop);
  }
</pre>
<p>Finally, we'll write a simple producer and consumer which use
<tt class="literal">shm_queue</tt>:</p>
<pre class="programlisting">
  struct Message {
      int sequence_num;
      shm_ptr&lt;char&gt; message;
  };

  // main routine for producer
  int main(int argc, char*argv[]) {
      shm_segment seg(30000, shm_segment::CreateOwned, 1000000);
      shm_allocator a(seg);
      shm_queue&lt;Message&gt; q(a);
      int message_count = 0;
      while (true) {
          std::cout &lt;&lt; &quot;enter a message: &quot;
                    &lt;&lt; std::flush;
          std::string line;
          std::getline(std::cin, line);
          Message* m = new (a) Message;
          m-&gt;sequence_num = message_count++;
          m-&gt;message.reset(static_cast&lt;char*&gt;(a.alloc(line.size()+1)), seg);
          strcpy(m-&gt;message.get(seg), line.c_str());
          q.push(shm_ptr&lt;Message&gt;(m, seg));
      }
  }

  // main routine for consumer
  int main(int argc, char*argv[]) {
      shm_segment seg(30000, shm_segment::NoCreate);
      shm_allocator a(seg);
      shm_queue&lt;Message&gt; q(a);
      while (true) {
          shm_ptr&lt;Message&gt; p = q.pop();
          Message* m = p.get(seg);
          std::cout &lt;&lt; &quot;Message &quot;
                    &lt;&lt; m-&gt;sequence_num
                    &lt;&lt; &quot; &quot;
                    &lt;&lt; m-&gt;message.get(seg)
                    &lt;&lt; &quot;\n&quot;;
          a.free(m-&gt;message.get(seg));
          m-&gt;~Message();
          operator delete(m, a);
      }
  }
</pre>
<p>There you have it: a way to access shared memory, allocate
objects in it, and pass them on a queue. So keep up with your
reading, and pay attention to the ACCU book reviews [<a href=
"#BookRev">BookRev</a>]!</p>
</div>
<div class="sect1" lang="en">
<div class="titlepage">
<h2><a name="d0e311" id=
"d0e311"></a>Acknowledgements</h2>
</div>
<p>Special thanks to Satish Kalipatnapu and Thad Frogley for the
valuable comments they provided on drafts of this article. Any
errors that remain are mine alone.</p>
<div class="bibliography">
<div class="titlepage">
<h2><a name="d0e316" id="d0e316"></a>References</h2>
</div>
<div class="bibliomixed"><a name="Stevens" id="Stevens"></a>
<p class="bibliomixed">[Stevens] W. Richard Stevens: <span class=
"citetitle"><i class="citetitle">UNIX Network Programming, Volume
2: Interprocess Communications</i></span>, Prentice Hall, 1998,
ISBN 0-130-81081-9.</p>
</div>
<div class="bibliomixed"><a name="Alexandrescu" id=
"Alexandrescu"></a>
<p class="bibliomixed">[Alexandrescu] Andrei Alexandrescu:
<span class="citetitle"><i class="citetitle">Modern C++ Design:
Generic Programming and Design Patterns Applied</i></span>,
Addison-Wesley, 2000, ISBN 0-201-70431-5.</p>
</div>
<div class="bibliomixed"><a name="Knuth" id="Knuth"></a>
<p class="bibliomixed">[Knuth] Donald E. Knuth: <span class=
"citetitle"><i class="citetitle">The Art of Computer
Programming</i></span>, Addison-Wesley, 1998, ISBN
0-201-48541-9</p>
</div>
<div class="bibliomixed"><a name="KandR" id="KandR"></a>
<p class="bibliomixed">[KandR] Brian W. Kernighan and Dennis M.
Ritchie: <span class="citetitle"><i class="citetitle">The C
Programming Language</i></span>, Prentice Hall, 1988, ISBN
0-131-10362-8.</p>
</div>
<div class="bibliomixed"><a name="Sutter" id="Sutter"></a>
<p class="bibliomixed">[Sutter] Herb Sutter: <span class=
"citetitle"><i class="citetitle">Exceptional C++: 47 Engineering
Puzzles, Programming Problems, and Solutions</i></span>,
Addison-Wesley, 2000, ISBN 0-201-61562-2.</p>
</div>
<div class="bibliomixed"><a name="Butenhof" id="Butenhof"></a>
<p class="bibliomixed">[Butenhof] David R. Butenhof: <span class=
"citetitle"><i class="citetitle">Programming with POSIX
Threads</i></span>, Addison-Wesley, 1997, ISBN 0-201-63392-2.</p>
</div>
<div class="bibliomixed"><a name="BookRev" id="BookRev"></a>
<p class="bibliomixed">[BookRev] <span class="bibliomisc"><a href=
"http://www.accu.org/bookreviews/public/index.htm" target=
"_top">http://www.accu.org/bookreviews/public/index.htm</a></span></p>
</div>
</div>
</div>
<div class="footnotes"><br>
<hr class="c4" width="100">
<div class="footnote">
<p><sup>[<a name="ftn.d0e26" href="#d0e26" id=
"ftn.d0e26">1</a>]</sup> Actually, I also had some prior experience
using shared memory, so this may just be a case of everything
looking like a nail when all you have is a hammer.</p>
</div>
<div class="footnote">
<p><sup>[<a name="ftn.d0e66" href="#d0e66" id=
"ftn.d0e66">2</a>]</sup> Some people insist that all Unix system
calls can be pronounced as they are written, no matter how
vowel-deficient they may be.</p>
</div>
<div class="footnote">
<p><sup>[<a name="ftn.d0e143" href="#d0e143" id=
"ftn.d0e143">3</a>]</sup> Unfortunately, the small object allocator
in Loki (the C++ library developed in [<a href=
"#Alexandrescu">Alexandrescu</a>]) appears to have a few unresolved
implementation issues. If you choose to use it, you may learn more
than you ever wanted about allocators. However, this does not
detract from the value of &quot;Modern C++ Design&quot; itself.</p>
</div>
<div class="footnote">
<p><sup>[<a name="ftn.d0e241" href="#d0e241" id=
"ftn.d0e241">4</a>]</sup> Item 10 in [<a href="#Sutter">Sutter</a>]
warns against returning objects in <tt class="literal">pop()</tt>
methods. However, in this case, it is not necessary to provide
separate <tt class="literal">top()</tt> and <tt class=
"literal">pop()</tt> methods; since we only store pointers the
<tt class="literal">pop()</tt> operation cannot throw an exception
while copying the return value.</p>
</div>
<div class="footnote">
<p><sup>[<a name="ftn.d0e279" href="#d0e279" id=
"ftn.d0e279">5</a>]</sup> An alternative synchronization method is
to use Unix semaphores instead of mutexes and condition variables
(semaphores can simulate either). I presented Pthreads here because
it is cleaner both conceptually and for implementation.</p>
</div>
</div>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
