diff options
-rw-r--r-- | ChangeLog-98b | 9 | ||||
-rw-r--r-- | docs/tutorials/021/client.cpp | 64 | ||||
-rw-r--r-- | docs/tutorials/021/combine.shar | 228 | ||||
-rw-r--r-- | docs/tutorials/021/mpool.cpp | 31 | ||||
-rw-r--r-- | docs/tutorials/021/mpool.h | 28 | ||||
-rw-r--r-- | docs/tutorials/021/page01.html | 28 | ||||
-rw-r--r-- | docs/tutorials/021/page02.html | 172 | ||||
-rw-r--r-- | docs/tutorials/021/page03.html | 132 | ||||
-rw-r--r-- | docs/tutorials/021/page04.html | 88 | ||||
-rw-r--r-- | docs/tutorials/021/page05.html | 91 | ||||
-rw-r--r-- | docs/tutorials/021/page06.html | 32 | ||||
-rw-r--r-- | docs/tutorials/021/server.cpp | 83 | ||||
-rw-r--r-- | docs/tutorials/online-tutorials.html | 2 |
13 files changed, 936 insertions, 52 deletions
diff --git a/ChangeLog-98b b/ChangeLog-98b index 9733d2f9131..714490c5317 100644 --- a/ChangeLog-98b +++ b/ChangeLog-98b @@ -1,3 +1,12 @@ +Wed Jan 6 14:27:24 EST 1999 James CE Johnson <jcej@lads.com + + * docs/tutorials/021/*: + Completed the ACE_Malloc<> tutorial. It could be a lot better + than it is but I'm still new to ACE_Malloc... + + * docs/tutorials/021/online-tutorials.html: + Added the link for #21 + Tue Jan 05 22:55:07 1999 Irfan Pyarali <irfan@cs.wustl.edu> * ace/Strategies_T.cpp (cleanup_hint_i and check_hint_i): Since we diff --git a/docs/tutorials/021/client.cpp b/docs/tutorials/021/client.cpp index 10d8cd99859..d5d80b58a91 100644 --- a/docs/tutorials/021/client.cpp +++ b/docs/tutorials/021/client.cpp @@ -5,42 +5,84 @@ int main (int, char *[]) { + /* + Use the same pool name used by the server when we create our + Allocator. This assures us that we don't create a whole new + pool. + */ Allocator allocator(Constants::PoolName); - + + /* + You can put anything in the memory pool. Not just the + character array we want. The find() method till, therefore, + return a void* that we will have to cast. + */ void * region; - + + /* + We use find() to locate a named region in the pool. This is + the counterpart to bind() used in the server. + Here, we go try to find the region that the server has created + and filled with data. If there was a problem getting the pool + or finding the region, we'll get back -1 from find(). + */ if( allocator.pool().find(Constants::RegionName,region) == -1 ) { ACE_ERROR_RETURN ((LM_ERROR, "Cannot find the name '%s'\n", Constants::RegionName), 100 ); } - + + /* + Since find() returns us a void*, we cast it here to the char* + that we want. + */ char *shm = (char *)region; ACE_DEBUG ((LM_INFO, "Shared memory is at 0x%x\n", shm )); + /* + The same pair of semaphores as used by the server are created + here. We probably don't need the CREATE flag since the server + should have already done that. There may be some very small + windows, however, where the server would have created the + memory pool but not yet gotten to the semaphores. + */ ACE_SV_Semaphore_Complex mutex; - // This semaphore is initially created with a count of 0, i.e., it - // is "locked." ACE_ASSERT (mutex.open (Constants::SEM_KEY_1, ACE_SV_Semaphore_Complex::ACE_CREATE, 0) != -1); ACE_SV_Semaphore_Complex synch; - // This semaphore is initially created with a count of 0, i.e., it - // is "locked." ACE_ASSERT (synch.open (Constants::SEM_KEY_2, ACE_SV_Semaphore_Complex::ACE_CREATE, 0) != -1); + /* + It doesn't matter if we created 'mutex' or if the server did. + In either case, it was created in a locked state and we will + block here until somebody unlocks it. In our scenario, that + will have to be the server. + */ if (mutex.acquire () == -1) { ACE_ERROR_RETURN ((LM_ERROR, "(%P) client mutex.acquire"), 1); } - + + /* + Now that we know it is safe to access the data, we'll run + through and make sure that it contains what we think the server + supplied. + */ for (int i = 0; i < Constants::SHMSZ; i++) { ACE_ASSERT (Constants::SHMDATA[i] == shm[i]); } - + + /* + Look back at the server. After filling the region, it will + attempt to acquire the lock on 'synch'. It will wait there + until we release() the semaphore. That will allow it to remove + the pool and cleanup. We can simply exit once we perform the + release. (Ok, a free() of the region would probably be polite...) + */ if (synch.release () == -1) { ACE_ERROR_RETURN ((LM_ERROR, "(%P) client synch.release"), 1); @@ -49,6 +91,10 @@ int main (int, char *[]) return 0; } +/* + Again, we have the necessary explicit template instantiations + because I based this on an ACE example instead of creating it from scratch. + */ #if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) template class ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_SV_Semaphore_Simple>; template class ACE_Guard<ACE_SV_Semaphore_Simple>; diff --git a/docs/tutorials/021/combine.shar b/docs/tutorials/021/combine.shar index 78ee347ba71..5b92de500be 100644 --- a/docs/tutorials/021/combine.shar +++ b/docs/tutorials/021/combine.shar @@ -3,17 +3,22 @@ # To extract the files from this archive, save it to some FILE, remove # everything before the `!/bin/sh' line above, then type `sh FILE'. # -# Made on 1999-01-02 23:53 EST by <root@chiroptera.tragus.org>. -# Source directory was `/var/home/jcej/projects/ACE_wrappers/docs/tutorials/021'. +# Made on 1999-01-06 14:26 EST by <jcej@caldera.lads.com>. +# Source directory was `/scsiA/home/jcej/projects/ACE_wrappers/docs/tutorials/021'. # # Existing files will *not* be overwritten unless `-c' is specified. # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ -# 426 -rw-rw-r-- hdr -# 69 -rw-rw-r-- bodies -# 509 -rw-rw-r-- page01.pre +# 409 -rw-rw-r-- hdr +# 47 -rw-rw-r-- bodies +# 562 -rw-rw-r-- page01.pre +# 281 -rw-rw-r-- page02.pre +# 201 -rw-rw-r-- page03.pre +# 287 -rw-rw-r-- page04.pre +# 287 -rw-rw-r-- page05.pre +# 604 -rw-rw-r-- page06.pre # save_IFS="${IFS}" IFS="${IFS}:" @@ -60,7 +65,7 @@ else fi rm -f 1231235999 $$.touch # -if mkdir _sh26726; then +if mkdir _sh07125; then $echo 'x -' 'creating lock directory' else $echo 'failed to create lock directory' @@ -76,30 +81,30 @@ else <HEAD> X <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> X <META NAME="Author" CONTENT="James CE Johnson"> -X <TITLE>ACE Tutorial 020</TITLE> +X <TITLE>ACE Tutorial 021</TITLE> </HEAD> <BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> X -<CENTER><B><FONT SIZE=+2>ACE Tutorial 020</FONT></B></CENTER> +<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER> X -<CENTER><B><FONT SIZE=+2>Sharing your Memories with persistence</FONT></B></CENTER> +<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER> X <P> <HR WIDTH="100%"> SHAR_EOF - $shar_touch -am 1228173698 'hdr' && + $shar_touch -am 0103180599 'hdr' && chmod 0664 'hdr' || $echo 'restore of' 'hdr' 'failed' if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'hdr:' 'MD5 check failed' -edd6dc67f13434391cf73b7604485b80 hdr +9ffa6eb1308f4872f390b30f74a6de3b hdr SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'hdr'`" - test 426 -eq "$shar_count" || - $echo 'hdr:' 'original size' '426,' 'current size' "$shar_count!" + test 409 -eq "$shar_count" || + $echo 'hdr:' 'original size' '409,' 'current size' "$shar_count!" fi fi # ============= bodies ============== @@ -111,22 +116,22 @@ else PAGE=2 server.cpp client.cpp -server2.cpp client2.cpp -mmap.h mmap.cpp +mpool.h +mpool.cpp SHAR_EOF - $shar_touch -am 1228174898 'bodies' && + $shar_touch -am 0106135399 'bodies' && chmod 0664 'bodies' || $echo 'restore of' 'bodies' 'failed' if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'bodies:' 'MD5 check failed' -a5d087bf1c11cf431c082ba146f3c6aa bodies +470abefc6e5e401ad9ffdfa76e3ca143 bodies SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`" - test 69 -eq "$shar_count" || - $echo 'bodies:' 'original size' '69,' 'current size' "$shar_count!" + test 47 -eq "$shar_count" || + $echo 'bodies:' 'original size' '47,' 'current size' "$shar_count!" fi fi # ============= page01.pre ============== @@ -135,31 +140,190 @@ if test -f 'page01.pre' && test "$first_param" != -c; then else $echo 'x -' extracting 'page01.pre' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'page01.pre' && -X This tutorial mirrors the previous. Instead of using shared memory, -X this time we'll be using a memory-mapped file. +X The previous two tutorials were very primitive & basic. They +X showed very simple uses of shared memory and memory mapped +X files. X <p> -X The cool thing about doing it this way is that we gain -X persistence of memory even across reboots. I wonder if you -X could memory map a file that's mounted via NFS? +X If we move the level of abstraction up just a bit, the next +X thing we encounter is memory pools. ACE_Malloc<> provides +X this to us. X <p> -X Like the shared memory tutorial, this one is also very basic and -X primitive. I'm assuming you've read that one, so I'll just hit -X the high points this time through.. +X In this tutorial, we'll use ACE_Malloc<> to create a +X memory pool that is sharable between a client and server. We'll +X use a memory mapped file to provide the physical storage but +X shared memory works just as well. SHAR_EOF - $shar_touch -am 1228173898 'page01.pre' && + $shar_touch -am 0103180499 'page01.pre' && chmod 0664 'page01.pre' || $echo 'restore of' 'page01.pre' 'failed' if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'page01.pre:' 'MD5 check failed' -333a5e5f8be0a5b8dc66424a50e5b4bd page01.pre +83956a1b05e5f8823afbdb8a84d8ac11 page01.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`" - test 509 -eq "$shar_count" || - $echo 'page01.pre:' 'original size' '509,' 'current size' "$shar_count!" + test 562 -eq "$shar_count" || + $echo 'page01.pre:' 'original size' '562,' 'current size' "$shar_count!" fi fi -rm -fr _sh26726 +# ============= page02.pre ============== +if test -f 'page02.pre' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'page02.pre' '(file already exists)' +else + $echo 'x -' extracting 'page02.pre' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'page02.pre' && +X The key components for creating the memory pool are: +X <ul> +X <li>Create and name the pool +X <li>Allocate a chunk (region) of memory from the pool +X <li>Name the allocated region +X </ul> +X The rest of it is just critical sections and data manipulation. +<hr> +SHAR_EOF + $shar_touch -am 0103180899 'page02.pre' && + chmod 0664 'page02.pre' || + $echo 'restore of' 'page02.pre' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'page02.pre:' 'MD5 check failed' +1bde237d2082c2f88f4802965e0b393d page02.pre +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`" + test 281 -eq "$shar_count" || + $echo 'page02.pre:' 'original size' '281,' 'current size' "$shar_count!" + fi +fi +# ============= page03.pre ============== +if test -f 'page03.pre' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'page03.pre' '(file already exists)' +else + $echo 'x -' extracting 'page03.pre' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'page03.pre' && +X The client side is a little simpler than the server. Mainly +X because we don't try to delete the pool: +X <ul> +X <li>Create an Allocator to access the pool +X <li>Find the named region +X </ul> +<hr> +SHAR_EOF + $shar_touch -am 0106135499 'page03.pre' && + chmod 0664 'page03.pre' || + $echo 'restore of' 'page03.pre' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'page03.pre:' 'MD5 check failed' +bd3bbfe6dbece827f8259d394d89ff58 page03.pre +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pre'`" + test 201 -eq "$shar_count" || + $echo 'page03.pre:' 'original size' '201,' 'current size' "$shar_count!" + fi +fi +# ============= page04.pre ============== +if test -f 'page04.pre' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'page04.pre' '(file already exists)' +else + $echo 'x -' extracting 'page04.pre' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'page04.pre' && +X Everything common the server & client is kept here. In +X particular, the Constants class where we keep the names & +X semaphore keys. +X <p> +X The Allocator class is just a thin wrapper around +X ACE_Malloc<> that moves some of the details out of the +X application logic. +<hr> +SHAR_EOF + $shar_touch -am 0106135699 'page04.pre' && + chmod 0664 'page04.pre' || + $echo 'restore of' 'page04.pre' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'page04.pre:' 'MD5 check failed' +a95d570fb8b7aca15802d9abdba84b81 page04.pre +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`" + test 287 -eq "$shar_count" || + $echo 'page04.pre:' 'original size' '287,' 'current size' "$shar_count!" + fi +fi +# ============= page05.pre ============== +if test -f 'page05.pre' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'page05.pre' '(file already exists)' +else + $echo 'x -' extracting 'page05.pre' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'page05.pre' && +X Everything common the server & client is kept here. In +X particular, the Constants class where we keep the names & +X semaphore keys. +X <p> +X The Allocator class is just a thin wrapper around +X ACE_Malloc<> that moves some of the details out of the +X application logic. +<hr> +SHAR_EOF + $shar_touch -am 0106140399 'page05.pre' && + chmod 0664 'page05.pre' || + $echo 'restore of' 'page05.pre' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'page05.pre:' 'MD5 check failed' +a95d570fb8b7aca15802d9abdba84b81 page05.pre +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`" + test 287 -eq "$shar_count" || + $echo 'page05.pre:' 'original size' '287,' 'current size' "$shar_count!" + fi +fi +# ============= page06.pre ============== +if test -f 'page06.pre' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'page06.pre' '(file already exists)' +else + $echo 'x -' extracting 'page06.pre' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'page06.pre' && +X As you can see, using a memory pool is really rather easy. The +X most difficult part, as always, is with the synch mechanisms. +X <P> +X The other nice thing about ACE_Malloc<> is that you can swap +X between System V shared memory and memory mapped files just by +X changing the template parameters. The truly adventurous will +X likely find a runtime way of doing this. +X <p> +X +X <ul> +X <li><A HREF="Makefile">Makefile</A> +X <li><A HREF="server.cpp">server.cpp</A> +X <li><A HREF="client.cpp">client.cpp</A> +X <li><A HREF="mpool.h">mpool.h</A> +X <li><A HREF="mpool.cpp">mpool.cpp</A> +X </ul> +SHAR_EOF + $shar_touch -am 0106142499 'page06.pre' && + chmod 0664 'page06.pre' || + $echo 'restore of' 'page06.pre' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'page06.pre:' 'MD5 check failed' +68fa5365d4add68561720a1f24bb980f page06.pre +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page06.pre'`" + test 604 -eq "$shar_count" || + $echo 'page06.pre:' 'original size' '604,' 'current size' "$shar_count!" + fi +fi +rm -fr _sh07125 exit 0 diff --git a/docs/tutorials/021/mpool.cpp b/docs/tutorials/021/mpool.cpp index 13d88a576b6..c65b3a6c664 100644 --- a/docs/tutorials/021/mpool.cpp +++ b/docs/tutorials/021/mpool.cpp @@ -3,6 +3,10 @@ #include "mpool.h" +/* + Set the values of all of the constants. This guarantees that client + and server don't get confused. + */ const int Constants::SEM_KEY_1 = ACE_DEFAULT_SEM_KEY + 1; const int Constants::SEM_KEY_2 = ACE_DEFAULT_SEM_KEY + 2; @@ -12,6 +16,11 @@ const char * Constants::SHMDATA = "abcdefghijklmnopqrstuvwxyz"; const char * Constants::PoolName = "SharedMemoryPool"; const char * Constants::RegionName = "Alphabet"; +/* + We have to create a copy of the _name parameter in case the caller + has dynamically allocated it. The pool_ is set to NULL & will be + allocated by the accessor. + */ Allocator::Allocator( const char * _name ) : name_(ACE_OS::strdup(_name)), pool_(0) @@ -25,12 +34,27 @@ Allocator::Allocator( const char * _name ) Allocator::~Allocator(void) { - if( pool_ ) + /* + strdup() uses malloc(), so we must use free() to clean up. + */ + if( name_ ) { - free(pool_); + free(name_); } + + // delete doesn't really care if you give it a NULL pointer. + delete pool_; } +/* + Allocate the pool. Since we return a reference, we'll be in really + bad shape if the new fails. This is a great place to throw an + exception! + The other concern is thread safety. If two threads call here at + about the same time, we may create the pool twice. We can't use a + Singleton because we want to have multiple Allocator instances. The + Singleton techniques can be used though. + */ Allocator::pool_t & Allocator::pool(void) { if( ! pool_ ) @@ -38,8 +62,5 @@ Allocator::pool_t & Allocator::pool(void) pool_ = new pool_t( name_ ); } - // Obviously, we're assuming that the new above was - // successful. - return *pool_; } diff --git a/docs/tutorials/021/mpool.h b/docs/tutorials/021/mpool.h index 6530afefbd8..29b64437cdb 100644 --- a/docs/tutorials/021/mpool.h +++ b/docs/tutorials/021/mpool.h @@ -4,34 +4,58 @@ #ifndef MPOOL_H #define MPOOL_H +// Everything else we need is in this one header #include "ace/Malloc.h" -#include "ace/Singleton.h" +/* + With this we will abstract away some of the details of the memory + pool. Note that we don't treat this as a singleton because an + application may need more than one pool. Each would have a + different name and be used for different purposes. + */ class Allocator { public: + // The pool name will be used to create a unique semaphore to + // keep this pool separate from others. Allocator( const char * _name = "MemoryPool" ); ~Allocator(void); typedef ACE_Malloc<ACE_MMAP_Memory_Pool, ACE_SV_Semaphore_Simple> pool_t; + // Provide an accessor to the pool. This will also allocate the + // pool when first invoked. pool_t & pool(void); protected: + // The name we gave to the pool char * name_; + pool_t * pool_; }; +/* + The client and server need to agree on a certain set of values. By + placing them in the Constants class we can eliminate a bit of confusion. + */ class Constants { public: + // The semaphore keys are needed for the two semaphores that + // synch access to the shared memory area. static const int SEM_KEY_1; static const int SEM_KEY_2; - + + // How big the pool will be and what we'll put into it. A real + // app wouldn't need SHMDATA of course. static const int SHMSZ; static const char * SHMDATA; + // The name assigned to the memory pool by the server is needed + // by the client. Without it, the pool cannot be found. + // Likewise, the name the server will bind() to the region of the + // pool must be available to the client. static const char * PoolName; static const char * RegionName; }; diff --git a/docs/tutorials/021/page01.html b/docs/tutorials/021/page01.html new file mode 100644 index 00000000000..262bdeac5cc --- /dev/null +++ b/docs/tutorials/021/page01.html @@ -0,0 +1,28 @@ +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="Author" CONTENT="James CE Johnson"> + <TITLE>ACE Tutorial 021</TITLE> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> + +<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER> + +<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER> + +<P> +<HR WIDTH="100%"> + The previous two tutorials were very primitive & basic. They + showed very simple uses of shared memory and memory mapped + files. + <p> + If we move the level of abstraction up just a bit, the next + thing we encounter is memory pools. ACE_Malloc<> provides + this to us. + <p> + In this tutorial, we'll use ACE_Malloc<> to create a + memory pool that is sharable between a client and server. We'll + use a memory mapped file to provide the physical storage but + shared memory works just as well. +<P><HR WIDTH="100%"> +<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page02.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/021/page02.html b/docs/tutorials/021/page02.html new file mode 100644 index 00000000000..0321bae2b66 --- /dev/null +++ b/docs/tutorials/021/page02.html @@ -0,0 +1,172 @@ +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="Author" CONTENT="James CE Johnson"> + <TITLE>ACE Tutorial 021</TITLE> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> + +<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER> + +<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER> + +<P> +<HR WIDTH="100%"> + The key components for creating the memory pool are: + <ul> + <li>Create and name the pool + <li>Allocate a chunk (region) of memory from the pool + <li>Name the allocated region + </ul> + The rest of it is just critical sections and data manipulation. +<hr><PRE> + +<font color=red>// $Id$</font> + +<font color=red>/* + I've hidden the details in an Allocator class declared in mpool.h + We'll come to that a little later. +*/</font> +<font color=blue>#include</font> "<font color=green>mpool.h</font>" + +int main (int, char *[]) +{ + <font color=red>/* + Construction of an Allocator will create the memory pool and + provide it with a name. The Constants class is also + declared in mpool.h to keep server and client on the same + page. The name is used to generate a unique semaphore which + prevents simultaneous access to the pools housekeeping + information. (Note that you still have to provide your own + synch mechanisms for the data *you* put in the poo.) + */</font> + Allocator allocator(<font color=#008888>Constants::PoolName</font>); + + <font color=red>/* + The Allocator class provides the pool() member so that you + have access to the actual memory pool. A more robust + implementation would behave more as a bridge class but this + is good enough for what we're doing here. + Once you have a reference to the pool, the malloc() method + can be used to get some bytes. If successful, shm will + point to the data. Otherwise, it will be zero. + */</font> + char *shm = (char *) allocator.pool().malloc (27); + + ACE_ASSERT( shm != 0 ); + + <font color=red>/// FYI</font> + ACE_DEBUG ((LM_INFO, "<font color=green>Shared memory is at 0x%x\n</font>", shm )); + + <font color=red>/* + Something that we can do with a memory pool is map a name to + a region provided by malloc. By doing this, we can + communicate that name to the client as a rendezvous + location. Again, a member of Constants is used to keep the + client and server coordinated. + */</font> + if( allocator.pool().bind(<font color=#008888>Constants::RegionName</font>,shm) == -1 ) + { + ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>Cannot bind the name '%s' to the pointer 0x%x\n</font>", + <font color=#008888>Constants::RegionName</font>,shm), 100 ); + } + + <font color=red>/* + One of the best ways to synch between different processes is + through the use of semaphores. ACE_SV_Semaphore_Complex + hides the gory details and lets us use them rather easily. + + Here, we'll create two semaphores: mutex and synch. mutex + will be used to provide mutually exclusive access to the + shared region for writting/reading. synch will be used to + prevent the server from removing the memory pool before the + client is done with it. + + Both semaphores are created in an initially locked state. + */</font> + + ACE_SV_Semaphore_Complex mutex; + ACE_ASSERT (mutex.open (<font color=#008888>Constants::SEM_KEY_1</font>, + <font color=#008888>ACE_SV_Semaphore_Complex::ACE_CREATE</font>, 0) != -1); + + ACE_SV_Semaphore_Complex synch; + ACE_ASSERT (synch.open (<font color=#008888>Constants::SEM_KEY_2</font>, + <font color=#008888>ACE_SV_Semaphore_Complex::ACE_CREATE</font>, 0) != -1); + + <font color=red>/* + We know the mutex is locked because we created it that way. + Take a moment to write some data into the shared region. + */</font> + for (int i = 0; i < <font color=#008888>Constants::SHMSZ</font>; i++) + { + shm[i] = <font color=#008888>Constants::SHMDATA</font>[i]; + } + + <font color=red>/* + The client will be blocking on an acquire() of mutex. By + releasing it here, the client can go look at the shared data. + */</font> + if (mutex.release () == -1) + { + ACE_ERROR ((LM_ERROR, "<font color=green>(%P) %p</font>", "<font color=green>server mutex.release</font>")); + } + <font color=red>/* + Even though we created the synch semaphore in a locked + state, if we attempt to acquire() it, we will block. Our + design requires that the client release() synch when it is + OK for us to remove the shared memory. + */</font> + else if (synch.acquire () == -1) + { + ACE_ERROR ((LM_ERROR, "<font color=green>(%P) %p</font>", "<font color=green>server synch.acquire</font>")); + } + + <font color=red>/* + This will remove all of the memory pool's resources. In the + case where a memory mapped file is used, the physical file + will also be removed. + */</font> + if (allocator.pool ().remove () == -1) + { + ACE_ERROR ((LM_ERROR, "<font color=green>(%P) %p\n</font>", "<font color=green>server allocator.remove</font>")); + } + + <font color=red>/* + We now have to cleanup the semaphores we created. Use the + ipcs command to see that they did, indeed, go away after the + server exits. + */</font> + + if (mutex.remove () == -1) + { + ACE_ERROR ((LM_ERROR, "<font color=green>(%P) %p\n</font>", "<font color=green>server mutex.remove</font>")); + } + + if (synch.remove () == -1) + { + ACE_ERROR ((LM_ERROR, "<font color=green>(%P) %p\n</font>", "<font color=green>server synch.remove</font>")); + } + + return 0; + +} + +<font color=red>/* + This tutorial was created by shamelessly modifying one of the ACE + examples. Someone there had already created the necessary explicit + template instantiations & I don't want them to go to waste... + */</font> +<font color=blue>#if defined</font> (<font color=purple>ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION</font>) +template class ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_SV_Semaphore_Simple>; +template class ACE_Guard<ACE_SV_Semaphore_Simple>; +template class ACE_Write_Guard<ACE_SV_Semaphore_Simple>; +template class ACE_Read_Guard<ACE_SV_Semaphore_Simple>; +<font color=blue>#elif defined</font> (<font color=purple>ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA</font>) +<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_SV_Semaphore_Simple> +<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Guard<ACE_SV_Semaphore_Simple> +<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Write_Guard<ACE_SV_Semaphore_Simple> +<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Read_Guard<ACE_SV_Semaphore_Simple> +<font color=blue>#endif</font> <font color=red>/* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */</font> +</PRE> +<P><HR WIDTH="100%"> +<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page03.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/021/page03.html b/docs/tutorials/021/page03.html new file mode 100644 index 00000000000..017134a55e5 --- /dev/null +++ b/docs/tutorials/021/page03.html @@ -0,0 +1,132 @@ +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="Author" CONTENT="James CE Johnson"> + <TITLE>ACE Tutorial 021</TITLE> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> + +<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER> + +<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER> + +<P> +<HR WIDTH="100%"> + The client side is a little simpler than the server. Mainly + because we don't try to delete the pool: + <ul> + <li>Create an Allocator to access the pool + <li>Find the named region + </ul> +<hr><PRE> + +<font color=red>// $Id$</font> + +<font color=blue>#include</font> "<font color=green>mpool.h</font>" + +int main (int, char *[]) +{ + <font color=red>/* + Use the same pool name used by the server when we create our + Allocator. This assures us that we don't create a whole new + pool. + */</font> + Allocator allocator(<font color=#008888>Constants::PoolName</font>); + + <font color=red>/* + You can put anything in the memory pool. Not just the + character array we want. The find() method till, therefore, + return a void* that we will have to cast. + */</font> + void * region; + + <font color=red>/* + We use find() to locate a named region in the pool. This is + the counterpart to bind() used in the server. + Here, we go try to find the region that the server has created + and filled with data. If there was a problem getting the pool + or finding the region, we'll get back -1 from find(). + */</font> + if( allocator.pool().find(<font color=#008888>Constants::RegionName</font>,region) == -1 ) + { + ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>Cannot find the name '%s'\n</font>", + <font color=#008888>Constants::RegionName</font>), 100 ); + } + + <font color=red>/* + Since find() returns us a void*, we cast it here to the char* + that we want. + */</font> + char *shm = (char *)region; + + ACE_DEBUG ((LM_INFO, "<font color=green>Shared memory is at 0x%x\n</font>", shm )); + + <font color=red>/* + The same pair of semaphores as used by the server are created + here. We probably don't need the CREATE flag since the server + should have already done that. There may be some very small + windows, however, where the server would have created the + memory pool but not yet gotten to the semaphores. + */</font> + ACE_SV_Semaphore_Complex mutex; + ACE_ASSERT (mutex.open (<font color=#008888>Constants::SEM_KEY_1</font>, + <font color=#008888>ACE_SV_Semaphore_Complex::ACE_CREATE</font>, 0) != -1); + + ACE_SV_Semaphore_Complex synch; + ACE_ASSERT (synch.open (<font color=#008888>Constants::SEM_KEY_2</font>, + <font color=#008888>ACE_SV_Semaphore_Complex::ACE_CREATE</font>, 0) != -1); + + <font color=red>/* + It doesn't matter if we created 'mutex' or if the server did. + In either case, it was created in a locked state and we will + block here until somebody unlocks it. In our scenario, that + will have to be the server. + */</font> + if (mutex.acquire () == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P) client mutex.acquire</font>"), 1); + } + + <font color=red>/* + Now that we know it is safe to access the data, we'll run + through and make sure that it contains what we think the server + supplied. + */</font> + for (int i = 0; i < <font color=#008888>Constants::SHMSZ</font>; i++) + { + ACE_ASSERT (<font color=#008888>Constants::SHMDATA</font>[i] == shm[i]); + } + + <font color=red>/* + Look back at the server. After filling the region, it will + attempt to acquire the lock on 'synch'. It will wait there + until we release() the semaphore. That will allow it to remove + the pool and cleanup. We can simply exit once we perform the + release. (Ok, a free() of the region would probably be polite...) + */</font> + if (synch.release () == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P) client synch.release</font>"), 1); + } + + return 0; +} + +<font color=red>/* + Again, we have the necessary explicit template instantiations + because I based this on an ACE example instead of creating it from scratch. + */</font> +<font color=blue>#if defined</font> (<font color=purple>ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION</font>) +template class ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_SV_Semaphore_Simple>; +template class ACE_Guard<ACE_SV_Semaphore_Simple>; +template class ACE_Write_Guard<ACE_SV_Semaphore_Simple>; +template class ACE_Read_Guard<ACE_SV_Semaphore_Simple>; +<font color=blue>#elif defined</font> (<font color=purple>ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA</font>) +<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_SV_Semaphore_Simple> +<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Guard<ACE_SV_Semaphore_Simple> +<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Write_Guard<ACE_SV_Semaphore_Simple> +<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Read_Guard<ACE_SV_Semaphore_Simple> +<font color=blue>#endif</font> <font color=red>/* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */</font> +</PRE> +<P><HR WIDTH="100%"> +<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page04.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/021/page04.html b/docs/tutorials/021/page04.html new file mode 100644 index 00000000000..cc6d3c0fa17 --- /dev/null +++ b/docs/tutorials/021/page04.html @@ -0,0 +1,88 @@ +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="Author" CONTENT="James CE Johnson"> + <TITLE>ACE Tutorial 021</TITLE> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> + +<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER> + +<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER> + +<P> +<HR WIDTH="100%"> + Everything common the server & client is kept here. In + particular, the Constants class where we keep the names & + semaphore keys. + <p> + The Allocator class is just a thin wrapper around + ACE_Malloc<> that moves some of the details out of the + application logic. +<hr><PRE> + +<font color=red>// $Id$</font> + +<font color=blue>#ifndef</font> <font color=purple>MPOOL_H</font> +<font color=blue>#define</font> <font color=purple>MPOOL_H</font> + +<font color=red>// Everything else we need is in this one header</font> +<font color=blue>#include</font> "<font color=green>ace/Malloc.h</font>" + +<font color=red>/* + With this we will abstract away some of the details of the memory + pool. Note that we don't treat this as a singleton because an + application may need more than one pool. Each would have a + different name and be used for different purposes. + */</font> +class Allocator +{ +public: + <font color=red>// The pool name will be used to create a unique semaphore to</font> + <font color=red>// keep this pool separate from others.</font> + Allocator( const char * _name = "<font color=green>MemoryPool</font>" ); + ~Allocator(void); + + typedef ACE_Malloc<ACE_MMAP_Memory_Pool, ACE_SV_Semaphore_Simple> pool_t; + + <font color=red>// Provide an accessor to the pool. This will also allocate the</font> + <font color=red>// pool when first invoked.</font> + pool_t & pool(void); + +protected: + + <font color=red>// The name we gave to the pool</font> + char * name_; + + pool_t * pool_; +}; + +<font color=red>/* + The client and server need to agree on a certain set of values. By + placing them in the Constants class we can eliminate a bit of confusion. + */</font> +class Constants +{ +public: + <font color=red>// The semaphore keys are needed for the two semaphores that</font> + <font color=red>// synch access to the shared memory area.</font> + static const int SEM_KEY_1; + static const int SEM_KEY_2; + + <font color=red>// How big the pool will be and what we'll put into it. A real</font> + <font color=red>// app wouldn't need SHMDATA of course.</font> + static const int SHMSZ; + static const char * SHMDATA; + + <font color=red>// The name assigned to the memory pool by the server is needed</font> + <font color=red>// by the client. Without it, the pool cannot be found.</font> + <font color=red>// Likewise, the name the server will bind() to the region of the </font> + <font color=red>// pool must be available to the client.</font> + static const char * PoolName; + static const char * RegionName; +}; + +<font color=blue>#endif</font> +</PRE> +<P><HR WIDTH="100%"> +<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/021/page05.html b/docs/tutorials/021/page05.html new file mode 100644 index 00000000000..6e238fcc85b --- /dev/null +++ b/docs/tutorials/021/page05.html @@ -0,0 +1,91 @@ +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="Author" CONTENT="James CE Johnson"> + <TITLE>ACE Tutorial 021</TITLE> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> + +<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER> + +<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER> + +<P> +<HR WIDTH="100%"> + Everything common the server & client is kept here. In + particular, the Constants class where we keep the names & + semaphore keys. + <p> + The Allocator class is just a thin wrapper around + ACE_Malloc<> that moves some of the details out of the + application logic. +<hr><PRE> + +<font color=red>// $Id$ </font> + +<font color=blue>#include</font> "<font color=green>mpool.h</font>" + +<font color=red>/* + Set the values of all of the constants. This guarantees that client + and server don't get confused. + */</font> +const int <font color=#008888>Constants::SEM_KEY_1</font> = ACE_DEFAULT_SEM_KEY + 1; +const int <font color=#008888>Constants::SEM_KEY_2</font> = ACE_DEFAULT_SEM_KEY + 2; + +const int <font color=#008888>Constants::SHMSZ</font> = 27; +const char * <font color=#008888>Constants::SHMDATA</font> = "<font color=green>abcdefghijklmnopqrstuvwxyz</font>"; + +const char * <font color=#008888>Constants::PoolName</font> = "<font color=green>SharedMemoryPool</font>"; +const char * <font color=#008888>Constants::RegionName</font> = "<font color=green>Alphabet</font>"; + +<font color=red>/* + We have to create a copy of the _name parameter in case the caller + has dynamically allocated it. The pool_ is set to NULL & will be + allocated by the accessor. + */</font> +<font color=#008888>Allocator::Allocator</font>( const char * _name ) + : name_(<font color=#008888>ACE_OS::strdup</font>(_name)), + pool_(0) +{ + if( ! name_ ) + { + ACE_ERROR ((LM_ERROR, "<font color=green>(%P) %p</font>", + "<font color=green><font color=#008888>Allocator::Allocator</font> cannot strdup pool name</font>" )); + } +} + +<font color=#008888>Allocator::~Allocator</font>(void) +{ + <font color=red>/* + strdup() uses malloc(), so we must use free() to clean up. + */</font> + if( name_ ) + { + free(name_); + } + + <font color=red>// delete doesn't really care if you give it a NULL pointer.</font> + delete pool_; +} + +<font color=red>/* + Allocate the pool. Since we return a reference, we'll be in really + bad shape if the new fails. This is a great place to throw an + exception! + The other concern is thread safety. If two threads call here at + about the same time, we may create the pool twice. We can't use a + Singleton because we want to have multiple Allocator instances. The + Singleton techniques can be used though. + */</font> +<font color=#008888>Allocator::pool_t</font> & Allocator::pool(void) +{ + if( ! pool_ ) + { + pool_ = new pool_t( name_ ); + } + + return *pool_; +} +</PRE> +<P><HR WIDTH="100%"> +<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page06.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/021/page06.html b/docs/tutorials/021/page06.html new file mode 100644 index 00000000000..6b2b67963ef --- /dev/null +++ b/docs/tutorials/021/page06.html @@ -0,0 +1,32 @@ +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="Author" CONTENT="James CE Johnson"> + <TITLE>ACE Tutorial 021</TITLE> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> + +<CENTER><B><FONT SIZE=+2>ACE Tutorial 021</FONT></B></CENTER> + +<CENTER><B><FONT SIZE=+2>Pooling your memories</FONT></B></CENTER> + +<P> +<HR WIDTH="100%"> + As you can see, using a memory pool is really rather easy. The + most difficult part, as always, is with the synch mechanisms. + <P> + The other nice thing about ACE_Malloc<> is that you can swap + between System V shared memory and memory mapped files just by + changing the template parameters. The truly adventurous will + likely find a runtime way of doing this. + <p> + + <ul> + <li><A HREF="Makefile">Makefile</A> + <li><A HREF="server.cpp">server.cpp</A> + <li><A HREF="client.cpp">client.cpp</A> + <li><A HREF="mpool.h">mpool.h</A> + <li><A HREF="mpool.cpp">mpool.cpp</A> + </ul> +<P><HR WIDTH="100%"> +<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] </CENTER> diff --git a/docs/tutorials/021/server.cpp b/docs/tutorials/021/server.cpp index 84618985cff..15ced695af0 100644 --- a/docs/tutorials/021/server.cpp +++ b/docs/tutorials/021/server.cpp @@ -1,23 +1,67 @@ // $Id$ +/* + I've hidden the details in an Allocator class declared in mpool.h + We'll come to that a little later. +*/ #include "mpool.h" int main (int, char *[]) { + /* + Construction of an Allocator will create the memory pool and + provide it with a name. The Constants class is also + declared in mpool.h to keep server and client on the same + page. The name is used to generate a unique semaphore which + prevents simultaneous access to the pools housekeeping + information. (Note that you still have to provide your own + synch mechanisms for the data *you* put in the poo.) + */ Allocator allocator(Constants::PoolName); - + + /* + The Allocator class provides the pool() member so that you + have access to the actual memory pool. A more robust + implementation would behave more as a bridge class but this + is good enough for what we're doing here. + Once you have a reference to the pool, the malloc() method + can be used to get some bytes. If successful, shm will + point to the data. Otherwise, it will be zero. + */ char *shm = (char *) allocator.pool().malloc (27); ACE_ASSERT( shm != 0 ); + /// FYI ACE_DEBUG ((LM_INFO, "Shared memory is at 0x%x\n", shm )); + /* + Something that we can do with a memory pool is map a name to + a region provided by malloc. By doing this, we can + communicate that name to the client as a rendezvous + location. Again, a member of Constants is used to keep the + client and server coordinated. + */ if( allocator.pool().bind(Constants::RegionName,shm) == -1 ) { ACE_ERROR_RETURN ((LM_ERROR, "Cannot bind the name '%s' to the pointer 0x%x\n", Constants::RegionName,shm), 100 ); } + + /* + One of the best ways to synch between different processes is + through the use of semaphores. ACE_SV_Semaphore_Complex + hides the gory details and lets us use them rather easily. + + Here, we'll create two semaphores: mutex and synch. mutex + will be used to provide mutually exclusive access to the + shared region for writting/reading. synch will be used to + prevent the server from removing the memory pool before the + client is done with it. + + Both semaphores are created in an initially locked state. + */ ACE_SV_Semaphore_Complex mutex; ACE_ASSERT (mutex.open (Constants::SEM_KEY_1, @@ -26,26 +70,51 @@ int main (int, char *[]) ACE_SV_Semaphore_Complex synch; ACE_ASSERT (synch.open (Constants::SEM_KEY_2, ACE_SV_Semaphore_Complex::ACE_CREATE, 0) != -1); - + + /* + We know the mutex is locked because we created it that way. + Take a moment to write some data into the shared region. + */ for (int i = 0; i < Constants::SHMSZ; i++) { shm[i] = Constants::SHMDATA[i]; } - + + /* + The client will be blocking on an acquire() of mutex. By + releasing it here, the client can go look at the shared data. + */ if (mutex.release () == -1) { ACE_ERROR ((LM_ERROR, "(%P) %p", "server mutex.release")); } + /* + Even though we created the synch semaphore in a locked + state, if we attempt to acquire() it, we will block. Our + design requires that the client release() synch when it is + OK for us to remove the shared memory. + */ else if (synch.acquire () == -1) { ACE_ERROR ((LM_ERROR, "(%P) %p", "server synch.acquire")); } - + + /* + This will remove all of the memory pool's resources. In the + case where a memory mapped file is used, the physical file + will also be removed. + */ if (allocator.pool ().remove () == -1) { ACE_ERROR ((LM_ERROR, "(%P) %p\n", "server allocator.remove")); } + /* + We now have to cleanup the semaphores we created. Use the + ipcs command to see that they did, indeed, go away after the + server exits. + */ + if (mutex.remove () == -1) { ACE_ERROR ((LM_ERROR, "(%P) %p\n", "server mutex.remove")); @@ -55,10 +124,16 @@ int main (int, char *[]) { ACE_ERROR ((LM_ERROR, "(%P) %p\n", "server synch.remove")); } + return 0; } +/* + This tutorial was created by shamelessly modifying one of the ACE + examples. Someone there had already created the necessary explicit + template instantiations & I don't want them to go to waste... + */ #if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) template class ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_SV_Semaphore_Simple>; template class ACE_Guard<ACE_SV_Semaphore_Simple>; diff --git a/docs/tutorials/online-tutorials.html b/docs/tutorials/online-tutorials.html index c6b0ef0bb6a..7aa97414562 100644 --- a/docs/tutorials/online-tutorials.html +++ b/docs/tutorials/online-tutorials.html @@ -128,6 +128,8 @@ Do you remember...</H4> <A HREF="019/page01.html">Using System V Shared Memory for telepathy</A> <LI> <A HREF="020/page01.html">Never forget anything else again!</A> +<LI> +<A HREF="021/page01.html">Pooling your memories via ACE_Malloc</A> </OL> <HR> |