    <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  :: Shared Memory Class</title>
        <link>https://members.accu.org/index.php/journals/1442</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 #4 - Feb 1994 + 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/c233/">04</a>
                    (11)
<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/c233-65/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/journals/c233+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;Shared Memory Class</h1>
<p><strong>Author:</strong>&nbsp;</p>
<p>
<strong>Date:</strong> 01 February 1994 08:55:00 +00:00 or Tue, 01 February 1994 08:55:00 +00:00</p>
<p><strong>Summary:</strong>&nbsp;</p>
<p><strong>Body:</strong>&nbsp;<p>With each class I finish, I'm more convinced the ease which a class
interface integrates into application designs, performs common actions
and prevents common mistakes should take precedence over the internal
class design. So, before I write an operating system class interface I
use the underlying C facilities and other implementations of similar
classes a while to recognise their weaknesses and then make up several
candidate class designs. I try including each of these candidates in
imaginary applications to select and hone the best of these interfaces,
only then do I begin to write the class implementation.</p>
<p>Such was the case for this shared memory class. I needed one for a
message queue in an operating system simulation. I read a few books on
the subject, tried a few classes written by others but ended up writing
my own. In this article, I present a this class facilitating the use of
shared memory and a rudimentary integration of shared memory and the
semaphores from the last issue. The flaws of contention management
design will be readily apparent, I hope you'll think about them and
send me your suggestions for improvement. With your help, I hope to
present a more useful shared memory management scheme in the future.
Your feedback will ensure that scheme will be generally useful. Without
further ado, here's the shared memory class, common_memory_region.</p>
<pre>#ifndef OS_SHAREDMEMORY_H <br>#define OS_SHAREDMEMORY_H <br>/***********************************************<br>* os_shm.h<br>* Will allocate a shared memory region and<br>* assign space for structures and variables<br>* listed in this header file. You must also<br>* indicate which processes will have access<br>* to the shared region, in what manner they<br>* will have access, and provide ptrs for<br>* those programs to access the data they are<br>* interested in.<br>#include &lt;sys/types.h&gt;<br>#include &lt;sys/ipc.h&gt;<br>// May need extern &quot;C&quot; declaration<br>#include &lt;sys/shm.h&gt;<br>// outside SYSV<br>enum cmr_perm<br>// Take from ipc.h and shm.h<br>{<br>  CMR_RW_ALL = (0400 | 0200),<br>  NEWCMR_RW_ALL = (IPC_CREAT | CMR_RW_ALL),<br>  RW_OWNER = (00400 | 00200),<br>  NEW_CMR_RW_OWNER = ( IPC_CREAT | RW_OWNER)<br>};<br>  <br>class common_memory_region<br>{<br>public:<br>  common_memory_region() ;<br>  virtual ~common_memory_region();<br>  int cmr_server(int cmr_id,<br>                 int size_of_block, <br>                 cmr_perm access_rights); <br>  void *cmr_client(int id,<br>                   cmr_perm access_rights);<br> &nbsp;void *cmr_register_client(<br>                   cmr_perm access_rights);<br> &nbsp;int set_cmr(int id); <br>protected:<br>  virtual void shm_error (char *error_msg); <br>private:<br>  int server_established; <br>  int common_region_id; <br>  char *client_address; <br>  struct shmid_ds *cmr_information; <br>  int file_handle;<br>}; <br>#endif</pre>
<h2>Intro to Shared Memory</h2>
<p>Shared memory is designed, as its name implies to share information
via a region of memory addressable across process boundaries. While
shared memory is allocated, like regular memory it is not easily
extended. It is possible to create a sbrk equivalent how ever, since
support for this type of operation is not built into the shared memory
system call interface, extending the region necessitates either copying
its entire contents to a new, larger region and adjusting external
pointers or adding a second region and using a sophisticated memory
manager to map storage operations to the proper region. Of the two, the
second alternative seems superior and I may add such sophistication to
the memory manager but it hasn't happened yet.</p>
<h2>Design</h2>
<p>Whenever you work with interprocess communication, a robust design
becomes more important because run-time debugging will be difficult. A
example of how a class interface can help prevent run-time errors,
consider that the semaphore class provided with the shared memory class
does not protect itself against race conditions. That is, its behaviour
is undetermined if two processes attempt to become the server for a
semaphore id simultaneously. The client-server design of the shared
memory class attempts to prevent this problem.</p>
<p>To use this class, you must create a &quot;server&quot; and &quot;client&quot; for the
shared memory. Only one server can delete the memory region. The server
also designates the desired read write permissions clients may have.
Clients, when created, can request permission levels up to that allowed
by the server.</p>
<p>Servers cannot be removed until all the clients they serve have
detached. Clients on the other hand, can switch the shared memory
regions they address at run time by using the &quot;set_cmr&quot; method. After
using set_cmr, you must call &quot;cmr_register_client&quot;. When you cast the
return of this call, you will receive a pointer of the proper type for
the shared region and re-establish a shared memory connection with the
proper permissions. You must, however, make sure you keep track of what
shared objects are in use so you don't detach from a shared memory
region holding information you are using. Please note that nothing is
keeping you from storing objects of many types in a single region.
Doing so just requires a scheme for hiding the shared information type
when you want to use it. For simplicity's sake I either inherit shared
objects from a common type or, more typically, share only a single type
in a region.</p>
<p>If you examine the shared memory implementation, you may notice that
the default constructor doesn't seem to do very much. I could have not
had a default constructor, forced the user to specify the shared memory
parameters and created the shared memory region with the constructor. I
avoided that approach because it did not fit within the client server
paradigm I had found very useful when attempting to prevent run-time
errors. Including a default constructor also allows a programmer to
allocate arrays of an object in a known state. I debated the use of
fstream type permissions in this class but settled on a unique
specified type because some of those operators don't make sense in a
shared memory context. I could also have used the string parameters of
the C file interface but a class specific enumeration will allow the
compiler to catch the passing of some bad permissions. Clients who
attempt to attach with unallowed permissions can only be detected at
runtime.</p>
<p>I could also have constructed a &quot;malloc&quot; and &quot;free&quot; method in the
class such as used in the C++ Wrappers distribution (see end of
article) However, beginning with C++ 2.1, a placement operator was made
available. This feature allows you to specify the address at which an
object is to be &quot;allocated&quot;. I've included such a new in this shared
memory class. An equivalent delete is not required, placed objects can
be treated like an other as long as you remember to address the
deletion of the underlying storage in the class destructor. I chose
this strategy because I wanted the interface to make the allocation of
shared memory and the ability of the region to hold disparate objects
obvious and explicit. Now I'll cover the lessons I've learned at the
IPC School of Hard Knocks.</p>
<h2>Subtle Issues</h2>
<p>The details contained so far in the presentation of the class should
be enough to allow you to use the class without further ado. However,
as I stated there, the common_memory_region interface allows access
only to the most often used shared memory facilities. The operating
system provides significantly more features. This section also contains
some of the subtle limitations imposed on the use of shared memory
segments by the operating system and the class interface.</p>
<p>First, some limitations of shared memory. There are two operating
system parameters, most commonly called SHMSEG_MAX and SHMAT_ MAX which
may affect your use of shared segments. (The name and value of these
parameters will vary from operating system to operating system. You can
also count on these kernel parameters being defined in a different file
location for each system. Maybe the common UNIX API will create a
common system configuration system- let's hope so.) SHMSEG_MAX governs
the maximum number of shared segments that can be present
simultaneously. SHMAT_MAX limits the number of shared segments which a
single process may attach to. On my machine (SVR4) these parameters are
stored in /etc/conf/cf.d/mtune and the parameter names are SHMMNI and
SHMSET. On an SGI they are stored in /usr/sysgen/master.d/shm and
called SHMMNI and SHMSEG. About the only way to gather this information
is to poke around the man pages of your system. I've included a utility
(limits) which will examine these limits. This small utility can serve
as a portability test and a method of finding the limits of your system
without spending hours hacking. While both these limits are beyond the
requirements of most applications, if you think you'll be bumping up
against these limits on your system it's likely you'll be taxing
others' systems as well. It's probably a better idea to redesign your
application than require the other users to rebuild their kernel to
install your software.</p>
<p>Forking off new processes and exec require some caution. If you fork
a thread or new process, the shared segments and any associated
semaphores will still be available in the new thread. Unlike forked
execution paths, a process which is started using any of the exec
family of calls will not be attached to the shared memory segments of
its parent. This behaviour is logical but worth noting.</p>
<p>Classes with virtual functions may also have problems with being
stored in shared memory. If such a class is to be shared, fork threads
using the shared classes from the same parent and be sure to double
check the validity of shared values during testing. This problem is
generic, the solution may be compiler specific, depending on the scheme
used to track virtual method pointers. You can see JOOP 91 for a more
complete discussion of the problem. It hasn't been an issue for me so
far, but fair warning.</p>
<p>A shared memory structure has a data structure, shmid_ds associated
with int. This data structure contains among other information the
current owner and user, process and group process which created the
region. The system call interface allows you to change the current
owner of the region. shmid_ds also contains information on the number
of processes attached to the shared region . You can see this call in
the class destructor where I use it to determine if the server should
destroy the region or just decrement the reference count. shmid_ds also
contains information on the time of the last attach and unattach
actions and when the id information was last changed. I have never had
occasion to use any of these facilities but feel free to add a free
form method to common_memory_region for access to these and other
facilities if you think you need them. If you do, please let me know as
I'm interested in how they'd be useful.</p>
<h2>Build Notes</h2>
<p>I've built this library on a Sun using 4.1, DECs using ULTRIX 4.3
and 4.3 BSD, an SGI using 4.0.5 and UNIX/386 (SVR4) machines. It should
build without modification on any UNIX machine offering network and IPC
services. The library will compile with g++ or CC 3.0 using gmake or
regular make. I haven't built it with GNU libc or GNU Id although there
is no reason why it shouldn't compile with those tools (and thus LINUX
and BSD/386) as well. If you notice non-portable aspects of the tools,
have enhancement suggestions, or, heaven forbid bugs, please drop me a
note and I'll get to work on the problem.</p>
<h2>Other Implementations</h2>
<p>No class is perfect, if you don't like this one or simply want to
see how others have implemented the same functionality, here are a
couple of FTP sites which carry other implementations. These may
require some porting to compile on your platform. I've included each of
these in the code I sent to Francis. If he has room I'm sure he'll put
them on the code disk.</p>
<p>C++wrappers-2.4: ics.uci.edu.</p>
<p>SharedCoreManager: svr- ftp.eng.cam.ac.uk. I pulled the limits
utility from here</p>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
