diff options
author | jcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1999-02-14 19:29:11 +0000 |
---|---|---|
committer | jcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1999-02-14 19:29:11 +0000 |
commit | 2e223ec826333dcedd350bd3df4f7a7e1e9161f2 (patch) | |
tree | 893c8b286dfae9b29b34d22dfd256a95ee2fcf8f | |
parent | 33864ee7505873b3bc93d5d40b9aad7fc17d4888 (diff) | |
download | ATCD-2e223ec826333dcedd350bd3df4f7a7e1e9161f2.tar.gz |
*** empty log message ***
35 files changed, 397 insertions, 356 deletions
diff --git a/ChangeLog-99b b/ChangeLog-99b index 6acf4f33134..8175dc351bf 100644 --- a/ChangeLog-99b +++ b/ChangeLog-99b @@ -1,3 +1,24 @@ +Sun Feb 14 14:09:11 1999 James CE Johnson <jcej@chiroptera.tragus.org> + + * docs/tutorials/015/server.cpp (main): Force the singleton to use + the Select Reactor instead of the OS-default. This should fix the + problem this tutorial has on Win32 due to blocking vs non-blocking + socket configuration. + + * docs/tutorials/015/Protocol_Task.h : Removed the ability to + activate this task. The code is now a little simpler and less + likely to behave in unpredicatable ways. + + * docs/tutorials/015/* : A few typos fixed but mostly fallout from + removing the ability to activate the Protocol_Task. + + * docs/tutorials/016/page01.html : Added Kirthika's abstract. + + * docs/tutorials/016/condition.cpp : Made max_threads_ a + non-static member variable that is set by open(). + + * docs/tutorials/017/page01.html : Added Kirthika's abstract. + Sun Feb 14 12:47:03 1999 Carlos O'Ryan <coryan@cs.wustl.edu> * ace/CDR_Stream.h: diff --git a/docs/tutorials/015/Compressor.cpp b/docs/tutorials/015/Compressor.cpp index f93d44009de..931264d716c 100644 --- a/docs/tutorials/015/Compressor.cpp +++ b/docs/tutorials/015/Compressor.cpp @@ -4,11 +4,8 @@ #include "Compressor.h" #include "ace/SOCK_Stream.h" -/* Construct our baseclass with the proper thread count. I really - should remove this option... - */ -Compressor::Compressor( int _thr_count ) - : Protocol_Task(_thr_count) +Compressor::Compressor( void ) + : Protocol_Task() { ; } diff --git a/docs/tutorials/015/Compressor.h b/docs/tutorials/015/Compressor.h index b822c6be59c..cb4c7248cce 100644 --- a/docs/tutorials/015/Compressor.h +++ b/docs/tutorials/015/Compressor.h @@ -14,14 +14,7 @@ public: typedef Protocol_Task inherited; - // I've given you the option of creating this task derivative - // with a number of threads. In retro-spect that really isn't - // a good idea. Most client/server systems rely on requests - // and responses happening in a predicatable order. Introduce - // a thread pool and message queue and that ordering goes - // right out the window. In other words: Don't ever use the - // constructor parameter! - Compressor (int thr_count = 0); + Compressor (void); ~Compressor (void); diff --git a/docs/tutorials/015/Crypt.cpp b/docs/tutorials/015/Crypt.cpp index 1967bbe0ff1..83cfd7ab73f 100644 --- a/docs/tutorials/015/Crypt.cpp +++ b/docs/tutorials/015/Crypt.cpp @@ -6,8 +6,8 @@ /* The expected constructor... */ -Crypt::Crypt( int _thr_count ) - : Protocol_Task(_thr_count) +Crypt::Crypt( void ) + : Protocol_Task() { } diff --git a/docs/tutorials/015/Crypt.h b/docs/tutorials/015/Crypt.h index 60aa82f69bd..6de997fa4a9 100644 --- a/docs/tutorials/015/Crypt.h +++ b/docs/tutorials/015/Crypt.h @@ -14,9 +14,7 @@ public: typedef Protocol_Task inherited; - // Again we have the option of multiple threads and again I - // regret tempting folks to use it. - Crypt (int thr_count = 0); + Crypt (void); ~Crypt (void); diff --git a/docs/tutorials/015/Handler.cpp b/docs/tutorials/015/Handler.cpp index ab141c7e8c2..0cfb3242c3d 100644 --- a/docs/tutorials/015/Handler.cpp +++ b/docs/tutorials/015/Handler.cpp @@ -54,7 +54,7 @@ int Handler::open (void *) // will prevent communicating with the client. This is // something you'll want to do in every event handler you create. if (this->peer ().get_remote_addr (addr) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't get remote addr\n"), -1); + ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) Cannot get remote addr\n"), -1); // Announce the client ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name() )); @@ -72,7 +72,7 @@ int Handler::open (void *) // stream's open() may fail. if( rval == -1 ) { - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't open the protocol stream.\n"), -1); + ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) Cannot open the protocol stream.\n"), -1); } // Now that we know the client is valid and that the stream is @@ -80,7 +80,7 @@ int Handler::open (void *) // instance. Here again is an opportunity for improvement if // we expect to have mulitple Server object instances. if (ACE_Reactor::instance()->register_handler (this, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1); + ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) Cannot register with reactor\n"), -1); return rval; } @@ -125,7 +125,7 @@ int Handler::handle_input (ACE_HANDLE) // will then be pushed through the protocol stream. if( stream().get( ) == -1 ) { - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't get data from protocol stream\n"), -1); + ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) Cannot get data from protocol stream\n"), -1); } return 0; @@ -138,10 +138,10 @@ int Handler::handle_input (ACE_HANDLE) several peers, however, you're probably just wasting a thread to activate it. On the other hand, if your reactor is running in a single thread (as in this example) then you can easily implement - thread-per-connectin concurrency by giving the baseclass one thread. + thread-per-connection concurrency by giving the baseclass one thread. */ Handler_Task::Handler_Task(void) - : inherited(0) + : inherited() { ; } diff --git a/docs/tutorials/015/Protocol_Stream.cpp b/docs/tutorials/015/Protocol_Stream.cpp index c82ab12335c..ed9b866a1bd 100644 --- a/docs/tutorials/015/Protocol_Stream.cpp +++ b/docs/tutorials/015/Protocol_Stream.cpp @@ -21,6 +21,16 @@ typedef ACE_Module<ACE_MT_SYNCH> Module; typedef ACE_Thru_Task<ACE_MT_SYNCH> Thru_Task; +/* An ACE_Stream is a collection of ACE_Modules. You can think of it + as a doubly-linked list if you like. Each Module contains two + ACE_Task derivatives. One of these tasks is used when sending data + "upstream", the other is used for "downstream" operation. In some + cases, you'll only need to move data in one direction. To provide + a placeholder for the other direction, ACE_Thru_Task can be used. + ACE_Thru_Task responds to the put() by simply invoking put_next() + to send the data to the next module. + */ + /* Do-nothing constructor and destructor */ @@ -47,14 +57,14 @@ Protocol_Stream::open (ACE_SOCK_Stream &peer, // Construct (and remember) the Recv object so that we can read from // the peer(). ACE_NEW_RETURN (recv_, - Recv (peer ()), + Recv ( this->peer ()), -1); // Add the transmit and receive tasks to the head of the stream. As // we add more modules these will get pushed downstream and end up // nearest the tail by the time we're done. if (stream ().push (new Module ("Xmit/Recv", - new Xmit (peer ()), + new Xmit ( this->peer ()), recv_)) == -1) ACE_ERROR_RETURN ((LM_ERROR, "%p\n", diff --git a/docs/tutorials/015/Protocol_Task.cpp b/docs/tutorials/015/Protocol_Task.cpp index 3cfe7495539..b1eb82a43ad 100644 --- a/docs/tutorials/015/Protocol_Task.cpp +++ b/docs/tutorials/015/Protocol_Task.cpp @@ -4,113 +4,40 @@ #include "Protocol_Task.h" // Construct the object and remember the thread count. -Protocol_Task::Protocol_Task( int _thr_count ) - : desired_thr_count_(_thr_count) +Protocol_Task::Protocol_Task(void) { + ; } Protocol_Task::~Protocol_Task(void) { + ; } -// Activate the object if necessary. int Protocol_Task::open(void *arg) { ACE_UNUSED_ARG(arg); - if( desired_thr_count_ ) - { - return this->activate(THR_NEW_LWP, desired_thr_count_); - } - return(0); } -/* When we're being closed by the ACE_Stream and we've got threads to - worry about then we drop a hangup message onto the message queue so - that svc() will go away. Except for the call to is_active(), this - is lifted directly from Tutorial 14. -*/ int Protocol_Task::close(u_long flags) { - if (flags == 1 && is_active() ) - { - ACE_Message_Block *hangupBlock = new ACE_Message_Block(); - - hangupBlock->msg_type(ACE_Message_Block::MB_HANGUP); - - if (this->putq(hangupBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::close() putq"), -1); - } - - hangupBlock->release(); - - return this->wait(); - } - return 0; } -/* The put() method has to make a decision. If we've got threads then - put the unit of work onto the message queue for svc() to deal - with. If not then process() it directly. +/* When a message is put() onto the task, it's time to process() some data. */ int Protocol_Task::put(ACE_Message_Block *message,ACE_Time_Value *timeout) { - if( is_active() ) - { - return this->putq(message,timeout); - } - return this->process(message,timeout); } -/* svc() is about what you would expect. This is again lifted - directly from Tutorial 14 but with a call to process() for handling - the logic instead of doing the work right here. +/* Return an error since we don't want the task to ever be activated. */ int Protocol_Task::svc(void) { - ACE_Message_Block * message; - - while (1) - { - // Get a message - if ( this->getq(message, 0) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Protocol_Task::svc() getq"), -1); - } - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Protocol_Task::svc() got message\n")); - - // Check for hangup - if (message->msg_type() == ACE_Message_Block::MB_HANGUP) { - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Protocol_Task::svc() -- HANGUP block received\n")); - - // Hangup our thread-pool peers (if any) - if (this->putq(message->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Protocol_Task::svc() putq"), -1); - } - - // Leave svc() - break; - } - - // Do some work on the data. - if( this->process(message->duplicate(),0) == -1 ) - { - break; - } - - // Give up the message block before we go get another. - message->release(); - } - - // Give up the message block that caused us to exit the - // while(1) loop. - message->release(); - - return(0); + return -1; } /* There's nothing really magic about process(). We just decide if diff --git a/docs/tutorials/015/Protocol_Task.h b/docs/tutorials/015/Protocol_Task.h index 993cebb2e89..f886001678f 100644 --- a/docs/tutorials/015/Protocol_Task.h +++ b/docs/tutorials/015/Protocol_Task.h @@ -10,18 +10,16 @@ #endif /* ACE_LACKS_PRAGMA_ONCE */ /* A typical ACE_Task<> derivative that adds a few things appropriate - to protocol stacks. + to protocol stacks. To keep things a little simpler, we prevent + activation of the task and just borrow the thread of control from + the calling method in all cases. */ class Protocol_Task : public ACE_Task<ACE_MT_SYNCH> { public: typedef ACE_Task<ACE_MT_SYNCH> inherited; - // A choice of concurrency strategies is offered by the constructor. - // In most cases it makes sense to set this to zero and let things - // proceed serially. You might have a need, however, for some of - // your tasks to have their own thread. - Protocol_Task (int thr_count); + Protocol_Task (void); ~Protocol_Task (void); @@ -37,8 +35,8 @@ public: virtual int put (ACE_Message_Block *message, ACE_Time_Value *timeout); - // If you choose to activate the task then this method will be doing - // all of the work. + // We're obligated to provide this signature even though we won't be + // allowing this object to be activated. virtual int svc (void); protected: @@ -47,12 +45,6 @@ protected: int process (ACE_Message_Block *message, ACE_Time_Value *timeout); - // Just let us know if we're active or not. - int is_active (void) - { - return this->thr_count () != 0; - } - // Tasks on the writer (downstream) side of the stream are called // upon to send() data that will ultimately go to the peer. virtual int send (ACE_Message_Block *message, @@ -63,8 +55,6 @@ protected: virtual int recv (ACE_Message_Block *message, ACE_Time_Value *timeout); -private: - int desired_thr_count_; }; #endif /* PROTOCOL_TASK_H */ diff --git a/docs/tutorials/015/Recv.cpp b/docs/tutorials/015/Recv.cpp index 246968ddbf4..121e50c213b 100644 --- a/docs/tutorials/015/Recv.cpp +++ b/docs/tutorials/015/Recv.cpp @@ -8,7 +8,7 @@ initializations. */ Recv::Recv( ACE_SOCK_Stream & _peer ) - : Protocol_Task(0), peer_(_peer), error_(0) + : Protocol_Task(), peer_(_peer), error_(0) { // Create the tickler that get() will use to trigger recv() // through the baseclass. Since we're single-threaded this is @@ -47,7 +47,7 @@ int Recv::recv(ACE_Message_Block * message, ACE_Time_Value *timeout) int b = 0; /* Read from the socket one byte at a time until we see then - end-of-string NULL character. Since the OS layers (at leas + end-of-string NULL character. Since the OS layers (at least in Unix) will provide some buffering this isn't as bad as it may seem at first. @@ -55,7 +55,9 @@ int Recv::recv(ACE_Message_Block * message, ACE_Time_Value *timeout) WFMO_Reactor is used. This is because the socket has been placed into non-blocking mode and only the recv() of the first byte will block. The solution is to use - ACE_Select_Reactor and I hope to implement that soon. + ACE_Select_Reactor which doesn't change the socket + characteristics. We did that back in main(), so we should + be in good shape now. */ do { diff --git a/docs/tutorials/015/Server_i.cpp b/docs/tutorials/015/Server_i.cpp index 5f8303f9919..e71803b3d26 100644 --- a/docs/tutorials/015/Server_i.cpp +++ b/docs/tutorials/015/Server_i.cpp @@ -70,5 +70,6 @@ int Server::run(void) int Server::close(void) { finished_ = 1; + ACE_Reactor::instance()->notify(); return(0); } diff --git a/docs/tutorials/015/Xmit.cpp b/docs/tutorials/015/Xmit.cpp index 28cc7055ce6..9450fc00cf0 100644 --- a/docs/tutorials/015/Xmit.cpp +++ b/docs/tutorials/015/Xmit.cpp @@ -12,7 +12,7 @@ cause more trouble than you want to deal with. */ Xmit::Xmit( ACE_SOCK_Stream & _peer ) - : Protocol_Task(0), peer_(_peer) + : Protocol_Task(), peer_(_peer) { } diff --git a/docs/tutorials/015/combine.shar b/docs/tutorials/015/combine.shar index b8fe561dd48..68a509ce351 100644 --- a/docs/tutorials/015/combine.shar +++ b/docs/tutorials/015/combine.shar @@ -3,7 +3,7 @@ # 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-02-10 22:34 EST by <jcej@chiroptera.tragus.org>. +# Made on 1999-02-14 13:38 EST by <jcej@chiroptera.tragus.org>. # Source directory was `/var/home/jcej/projects/ACE_wrappers/docs/tutorials/015'. # # Existing files will *not* be overwritten unless `-c' is specified. @@ -13,7 +13,7 @@ # ------ ---------- ------------------------------------------ # 414 -rw-rw-r-- hdr # 419 -rw-rw-r-- bodies -# 4303 -rw-rw-r-- page01.pre +# 4228 -rw-rw-r-- page01.pre # 194 -rw-rw-r-- page02.pre # 318 -rw-rw-r-- page03.pre # 178 -rw-rw-r-- page04.pre @@ -83,7 +83,7 @@ else fi rm -f 1231235999 $$.touch # -if mkdir _sh29164; then +if mkdir _sh31334; then $echo 'x -' 'creating lock directory' else $echo 'failed to create lock directory' @@ -212,11 +212,12 @@ discussions. <P> Disclaimer: <br> -Several folks have reported problems with this tutorial on Win32. I -have the fixes in mind but may not get them in place until 2/8 or so. -What it amounts to is using the ACE_Select_Reactor for all platforms. -Win32 defaults to ACE_WFMO_Reactor and that seems to be causing some -or all of the problems. +<ul> +Several folks have reported problems with this tutorial on Win32. +There are a couple of ways to solve this. I've chosen to solve it by +using the ACE_Select_Reactor on all platforms instead of taking the +OS-default. +</ul> <P> Kirthika's abstract: <UL> @@ -277,19 +278,19 @@ etc.) X compression objects. I'll leave that as a thought X exercise!</font> SHAR_EOF - $shar_touch -am 0210223099 'page01.pre' && + $shar_touch -am 0214124599 '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' -77d3deec35fab659429a2eef4ab5b679 page01.pre +a09c3ff1f21a90aab991e0f38dc00458 page01.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`" - test 4303 -eq "$shar_count" || - $echo 'page01.pre:' 'original size' '4303,' 'current size' "$shar_count!" + test 4228 -eq "$shar_count" || + $echo 'page01.pre:' 'original size' '4228,' 'current size' "$shar_count!" fi fi # ============= page02.pre ============== @@ -1058,5 +1059,5 @@ SHAR_EOF $echo 'page09.pst:' 'original size' '617,' 'current size' "$shar_count!" fi fi -rm -fr _sh29164 +rm -fr _sh31334 exit 0 diff --git a/docs/tutorials/015/page01.html b/docs/tutorials/015/page01.html index 40c62b39718..098d031d3ad 100644 --- a/docs/tutorials/015/page01.html +++ b/docs/tutorials/015/page01.html @@ -35,11 +35,12 @@ discussions. <P> Disclaimer: <br> -Several folks have reported problems with this tutorial on Win32. I -have the fixes in mind but may not get them in place until 2/8 or so. -What it amounts to is using the ACE_Select_Reactor for all platforms. -Win32 defaults to ACE_WFMO_Reactor and that seems to be causing some -or all of the problems. +<ul> +Several folks have reported problems with this tutorial on Win32. +There are a couple of ways to solve this. I've chosen to solve it by +using the ACE_Select_Reactor on all platforms instead of taking the +OS-default. +</ul> <P> Kirthika's abstract: <UL> diff --git a/docs/tutorials/015/page05.html b/docs/tutorials/015/page05.html index d13aaa80476..eddb65d8579 100644 --- a/docs/tutorials/015/page05.html +++ b/docs/tutorials/015/page05.html @@ -24,6 +24,7 @@ simplification. <font color=red>// $Id$</font> <font color=blue>#include</font> "<font color=green>Server_i.h</font>" +<font color=blue>#include</font> "<font color=green>ace/Select_Reactor.h</font>" <font color=red>// A signal handler that will close the server object</font> extern "<font color=green>C</font>" void handler (int) @@ -33,7 +34,28 @@ extern "<font color=green>C</font>" void handler (int) int main (int, char **) { - <font color=red>// The server object that abstracts away all of difficult parts.</font> + <font color=red>/* On Win32, the WFMO reactor is used by default. + Unfortunately, that causes the sockets to be put into + non-blocking mode which will break <font color=#008888>Recv::recv</font>(). To + prevent that issue, I explicitly use the Select Reactor + instead. I'll talk more about the "<font color=green>problem</font>" in the Recv + comments. + */</font> + + <font color=red>// First, we create a Select_Reactor that will do the work.</font> + <font color=red>// To keep things simple, I'll create it on the stack.</font> + ACE_Select_Reactor mySelectReactor; + + <font color=red>// Next, we need an ACE_Reactor that is the bridge between the </font> + <font color=red>// code and the real reactor. It is given a pointer to the</font> + <font color=red>// real reactor.</font> + ACE_Reactor myReactor (&mySelectReactor); + + <font color=red>// Finally, we set the singleton instance to use the reactor</font> + <font color=red>// we've created.</font> + <font color=#008888>ACE_Reactor::instance</font> (&myReactor); + + <font color=red>// The server object that abstracts away all of the difficult parts.</font> Server server; <font color=red>// Attempt to open the server. Like all good ACE-based</font> diff --git a/docs/tutorials/015/page07.html b/docs/tutorials/015/page07.html index 14f93a95731..06633974eb6 100644 --- a/docs/tutorials/015/page07.html +++ b/docs/tutorials/015/page07.html @@ -92,6 +92,7 @@ int <font color=#008888>Server::run</font>(void) int <font color=#008888>Server::close</font>(void) { finished_ = 1; + <font color=#008888>ACE_Reactor::instance</font>()->notify(); return(0); } </PRE> diff --git a/docs/tutorials/015/page09.html b/docs/tutorials/015/page09.html index 558ba8ce8c3..b8156b13271 100644 --- a/docs/tutorials/015/page09.html +++ b/docs/tutorials/015/page09.html @@ -80,7 +80,7 @@ int <font color=#008888>Handler::open</font> (void *) <font color=red>// will prevent communicating with the client. This is</font> <font color=red>// something you'll want to do in every event handler you create.</font> if (this->peer ().get_remote_addr (addr) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) can't get remote addr\n</font>"), -1); + ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) Cannot get remote addr\n</font>"), -1); <font color=red>// Announce the client</font> ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) connected with %s\n</font>", addr.get_host_name() )); @@ -98,7 +98,7 @@ int <font color=#008888>Handler::open</font> (void *) <font color=red>// stream's open() may fail.</font> if( rval == -1 ) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) can't open the protocol stream.\n</font>"), -1); + ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) Cannot open the protocol stream.\n</font>"), -1); } <font color=red>// Now that we know the client is valid and that the stream is </font> @@ -106,7 +106,7 @@ int <font color=#008888>Handler::open</font> (void *) <font color=red>// instance. Here again is an opportunity for improvement if</font> <font color=red>// we expect to have mulitple Server object instances.</font> if (<font color=#008888>ACE_Reactor::instance</font>()->register_handler (this, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) can't register with reactor\n</font>"), -1); + ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) Cannot register with reactor\n</font>"), -1); return rval; } @@ -151,7 +151,7 @@ int <font color=#008888>Handler::handle_input</font> (ACE_HANDLE) <font color=red>// will then be pushed through the protocol stream.</font> if( stream().get( ) == -1 ) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) can't get data from protocol stream\n</font>"), -1); + ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) Cannot get data from protocol stream\n</font>"), -1); } return 0; @@ -164,10 +164,10 @@ int <font color=#008888>Handler::handle_input</font> (ACE_HANDLE) several peers, however, you're probably just wasting a thread to activate it. On the other hand, if your reactor is running in a single thread (as in this example) then you can easily implement - thread-per-connectin concurrency by giving the baseclass one thread. + thread-per-connection concurrency by giving the baseclass one thread. */</font> <font color=#008888>Handler_Task::Handler_Task</font>(void) - : inherited(0) + : inherited() { ; } diff --git a/docs/tutorials/015/page11.html b/docs/tutorials/015/page11.html index f3225648a94..e03f1a5f7fe 100644 --- a/docs/tutorials/015/page11.html +++ b/docs/tutorials/015/page11.html @@ -42,6 +42,16 @@ concern in this file is to get everything in the correct order! typedef ACE_Module<ACE_MT_SYNCH> Module; typedef ACE_Thru_Task<ACE_MT_SYNCH> Thru_Task; +<font color=red>/* An ACE_Stream is a collection of ACE_Modules. You can think of it + as a doubly-linked list if you like. Each Module contains two + ACE_Task derivatives. One of these tasks is used when sending data + "<font color=green>upstream</font>", the other is used for "<font color=green>downstream</font>" operation. In some + cases, you'll only need to move data in one direction. To provide + a placeholder for the other direction, ACE_Thru_Task can be used. + ACE_Thru_Task responds to the put() by simply invoking put_next() + to send the data to the next module. + */</font> + <font color=red>/* Do-nothing constructor and destructor */</font> @@ -68,14 +78,14 @@ int <font color=red>// Construct (and remember) the Recv object so that we can read from</font> <font color=red>// the peer().</font> ACE_NEW_RETURN (recv_, - Recv (peer ()), + Recv ( this->peer ()), -1); <font color=red>// Add the transmit and receive tasks to the head of the stream. As</font> <font color=red>// we add more modules these will get pushed downstream and end up</font> <font color=red>// nearest the tail by the time we're done.</font> if (stream ().push (new Module ("<font color=green>Xmit/Recv</font>", - new Xmit (peer ()), + new Xmit ( this->peer ()), recv_)) == -1) ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", diff --git a/docs/tutorials/015/page12.html b/docs/tutorials/015/page12.html index 8dae49b5a18..07b36c3c9aa 100644 --- a/docs/tutorials/015/page12.html +++ b/docs/tutorials/015/page12.html @@ -27,18 +27,16 @@ A quick look at the Protocol_Task header... <font color=blue>#endif</font> <font color=red>/* ACE_LACKS_PRAGMA_ONCE */</font> <font color=red>/* A typical ACE_Task<> derivative that adds a few things appropriate - to protocol stacks. + to protocol stacks. To keep things a little simpler, we prevent + activation of the task and just borrow the thread of control from + the calling method in all cases. */</font> class Protocol_Task : public ACE_Task<ACE_MT_SYNCH> { public: typedef ACE_Task<ACE_MT_SYNCH> inherited; - <font color=red>// A choice of concurrency strategies is offered by the constructor.</font> - <font color=red>// In most cases it makes sense to set this to zero and let things</font> - <font color=red>// proceed serially. You might have a need, however, for some of</font> - <font color=red>// your tasks to have their own thread.</font> - Protocol_Task (int thr_count); + Protocol_Task (void); ~Protocol_Task (void); @@ -54,8 +52,8 @@ public: virtual int put (ACE_Message_Block *message, ACE_Time_Value *timeout); - <font color=red>// If you choose to activate the task then this method will be doing</font> - <font color=red>// all of the work.</font> + <font color=red>// We're obligated to provide this signature even though we won't be </font> + <font color=red>// allowing this object to be activated.</font> virtual int svc (void); protected: @@ -64,12 +62,6 @@ protected: int process (ACE_Message_Block *message, ACE_Time_Value *timeout); - <font color=red>// Just let us know if we're active or not.</font> - int is_active (void) - { - return this->thr_count () != 0; - } - <font color=red>// Tasks on the writer (downstream) side of the stream are called</font> <font color=red>// upon to send() data that will ultimately go to the peer.</font> virtual int send (ACE_Message_Block *message, @@ -80,8 +72,6 @@ protected: virtual int recv (ACE_Message_Block *message, ACE_Time_Value *timeout); -private: - int desired_thr_count_; }; <font color=blue>#endif</font> <font color=red>/* PROTOCOL_TASK_H */</font> diff --git a/docs/tutorials/015/page13.html b/docs/tutorials/015/page13.html index 967948e3d16..a6371dcc60a 100644 --- a/docs/tutorials/015/page13.html +++ b/docs/tutorials/015/page13.html @@ -25,113 +25,40 @@ only need one or two additional to do any real work. <font color=blue>#include</font> "<font color=green>Protocol_Task.h</font>" <font color=red>// Construct the object and remember the thread count.</font> -<font color=#008888>Protocol_Task::Protocol_Task</font>( int _thr_count ) - : desired_thr_count_(_thr_count) +<font color=#008888>Protocol_Task::Protocol_Task</font>(void) { + ; } <font color=#008888>Protocol_Task::~Protocol_Task</font>(void) { + ; } -<font color=red>// Activate the object if necessary.</font> int <font color=#008888>Protocol_Task::open</font>(void *arg) { ACE_UNUSED_ARG(arg); - if( desired_thr_count_ ) - { - return this->activate(THR_NEW_LWP, desired_thr_count_); - } - return(0); } -<font color=red>/* When we're being closed by the ACE_Stream and we've got threads to - worry about then we drop a hangup message onto the message queue so - that svc() will go away. Except for the call to is_active(), this - is lifted directly from Tutorial 14. -*/</font> int <font color=#008888>Protocol_Task::close</font>(u_long flags) { - if (flags == 1 && is_active() ) - { - ACE_Message_Block *hangupBlock = new ACE_Message_Block(); - - hangupBlock->msg_type(<font color=#008888>ACE_Message_Block::MB_HANGUP</font>); - - if (this->putq(hangupBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Task::close</font>() putq</font>"), -1); - } - - hangupBlock->release(); - - return this->wait(); - } - return 0; } -<font color=red>/* The put() method has to make a decision. If we've got threads then - put the unit of work onto the message queue for svc() to deal - with. If not then process() it directly. +<font color=red>/* When a message is put() onto the task, it's time to process() some data. */</font> int <font color=#008888>Protocol_Task::put</font>(ACE_Message_Block *message,ACE_Time_Value *timeout) { - if( is_active() ) - { - return this->putq(message,timeout); - } - return this->process(message,timeout); } -<font color=red>/* svc() is about what you would expect. This is again lifted - directly from Tutorial 14 but with a call to process() for handling - the logic instead of doing the work right here. +<font color=red>/* Return an error since we don't want the task to ever be activated. */</font> int <font color=#008888>Protocol_Task::svc</font>(void) { - ACE_Message_Block * message; - - while (1) - { - <font color=red>// Get a message</font> - if ( this->getq(message, 0) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Protocol_Task::svc</font>() getq</font>"), -1); - } - - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) <font color=#008888>Protocol_Task::svc</font>() got message\n</font>")); - - <font color=red>// Check for hangup</font> - if (message->msg_type() == <font color=#008888>ACE_Message_Block::MB_HANGUP</font>) { - - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) <font color=#008888>Protocol_Task::svc</font>() -- HANGUP block received\n</font>")); - - <font color=red>// Hangup our thread-pool peers (if any)</font> - if (this->putq(message->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Protocol_Task::svc</font>() putq</font>"), -1); - } - - <font color=red>// Leave svc()</font> - break; - } - - <font color=red>// Do some work on the data.</font> - if( this->process(message->duplicate(),0) == -1 ) - { - break; - } - - <font color=red>// Give up the message block before we go get another.</font> - message->release(); - } - - <font color=red>// Give up the message block that caused us to exit the</font> - <font color=red>// while(1) loop.</font> - message->release(); - - return(0); + return -1; } <font color=red>/* There's nothing really magic about process(). We just decide if diff --git a/docs/tutorials/015/page15.html b/docs/tutorials/015/page15.html index d186b712daf..bcc7a7aa207 100644 --- a/docs/tutorials/015/page15.html +++ b/docs/tutorials/015/page15.html @@ -43,7 +43,7 @@ streams of data. cause more trouble than you want to deal with. */</font> <font color=#008888>Xmit::Xmit</font>( ACE_SOCK_Stream & _peer ) - : Protocol_Task(0), peer_(_peer) + : Protocol_Task(), peer_(_peer) { } diff --git a/docs/tutorials/015/page17.html b/docs/tutorials/015/page17.html index c45e4a6eeb8..625bf84110c 100644 --- a/docs/tutorials/015/page17.html +++ b/docs/tutorials/015/page17.html @@ -28,7 +28,7 @@ basic stuff. initializations. */</font> <font color=#008888>Recv::Recv</font>( ACE_SOCK_Stream & _peer ) - : Protocol_Task(0), peer_(_peer), error_(0) + : Protocol_Task(), peer_(_peer), error_(0) { <font color=red>// Create the tickler that get() will use to trigger recv()</font> <font color=red>// through the baseclass. Since we're single-threaded this is</font> @@ -67,7 +67,7 @@ int <font color=#008888>Recv::recv</font>(ACE_Message_Block * message, ACE_Time_ int b = 0; <font color=red>/* Read from the socket one byte at a time until we see then - end-of-string NULL character. Since the OS layers (at leas + end-of-string NULL character. Since the OS layers (at least in Unix) will provide some buffering this isn't as bad as it may seem at first. @@ -75,7 +75,9 @@ int <font color=#008888>Recv::recv</font>(ACE_Message_Block * message, ACE_Time_ WFMO_Reactor is used. This is because the socket has been placed into non-blocking mode and only the recv() of the first byte will block. The solution is to use - ACE_Select_Reactor and I hope to implement that soon. + ACE_Select_Reactor which doesn't change the socket + characteristics. We did that back in main(), so we should + be in good shape now. */</font> do { diff --git a/docs/tutorials/015/page18.html b/docs/tutorials/015/page18.html index c19a1559750..d17427ffeeb 100644 --- a/docs/tutorials/015/page18.html +++ b/docs/tutorials/015/page18.html @@ -36,14 +36,7 @@ public: typedef Protocol_Task inherited; - <font color=red>// I've given you the option of creating this task derivative</font> - <font color=red>// with a number of threads. In retro-spect that really isn't</font> - <font color=red>// a good idea. Most client/server systems rely on requests</font> - <font color=red>// and responses happening in a predicatable order. Introduce</font> - <font color=red>// a thread pool and message queue and that ordering goes</font> - <font color=red>// right out the window. In other words: Don't ever use the</font> - <font color=red>// constructor parameter!</font> - Compressor (int thr_count = 0); + Compressor (void); ~Compressor (void); diff --git a/docs/tutorials/015/page19.html b/docs/tutorials/015/page19.html index 049bba13a06..e8689ebf9d7 100644 --- a/docs/tutorials/015/page19.html +++ b/docs/tutorials/015/page19.html @@ -24,11 +24,8 @@ things more difficult if something has to change in their interaction. <font color=blue>#include</font> "<font color=green>Compressor.h</font>" <font color=blue>#include</font> "<font color=green>ace/SOCK_Stream.h</font>" -<font color=red>/* Construct our baseclass with the proper thread count. I really - should remove this option... - */</font> -<font color=#008888>Compressor::Compressor</font>( int _thr_count ) - : Protocol_Task(_thr_count) +<font color=#008888>Compressor::Compressor</font>( void ) + : Protocol_Task() { ; } diff --git a/docs/tutorials/015/page20.html b/docs/tutorials/015/page20.html index 6b8917150e7..5a073600d10 100644 --- a/docs/tutorials/015/page20.html +++ b/docs/tutorials/015/page20.html @@ -37,9 +37,7 @@ public: typedef Protocol_Task inherited; - <font color=red>// Again we have the option of multiple threads and again I</font> - <font color=red>// regret tempting folks to use it.</font> - Crypt (int thr_count = 0); + Crypt (void); ~Crypt (void); diff --git a/docs/tutorials/015/page21.html b/docs/tutorials/015/page21.html index 5c7fc54eb27..951064b6922 100644 --- a/docs/tutorials/015/page21.html +++ b/docs/tutorials/015/page21.html @@ -25,8 +25,8 @@ favorite library. <font color=red>/* The expected constructor... */</font> -<font color=#008888>Crypt::Crypt</font>( int _thr_count ) - : Protocol_Task(_thr_count) +<font color=#008888>Crypt::Crypt</font>( void ) + : Protocol_Task() { } diff --git a/docs/tutorials/015/server.cpp b/docs/tutorials/015/server.cpp index bface44e341..4867833c220 100644 --- a/docs/tutorials/015/server.cpp +++ b/docs/tutorials/015/server.cpp @@ -2,6 +2,7 @@ // $Id$ #include "Server_i.h" +#include "ace/Select_Reactor.h" // A signal handler that will close the server object extern "C" void handler (int) @@ -11,7 +12,28 @@ extern "C" void handler (int) int main (int, char **) { - // The server object that abstracts away all of difficult parts. + /* On Win32, the WFMO reactor is used by default. + Unfortunately, that causes the sockets to be put into + non-blocking mode which will break Recv::recv(). To + prevent that issue, I explicitly use the Select Reactor + instead. I'll talk more about the "problem" in the Recv + comments. + */ + + // First, we create a Select_Reactor that will do the work. + // To keep things simple, I'll create it on the stack. + ACE_Select_Reactor mySelectReactor; + + // Next, we need an ACE_Reactor that is the bridge between the + // code and the real reactor. It is given a pointer to the + // real reactor. + ACE_Reactor myReactor (&mySelectReactor); + + // Finally, we set the singleton instance to use the reactor + // we've created. + ACE_Reactor::instance (&myReactor); + + // The server object that abstracts away all of the difficult parts. Server server; // Attempt to open the server. Like all good ACE-based diff --git a/docs/tutorials/016/Condition_i.h b/docs/tutorials/016/Condition_i.h index f1e5dad2bc1..2cd7adb21ba 100644 --- a/docs/tutorials/016/Condition_i.h +++ b/docs/tutorials/016/Condition_i.h @@ -12,7 +12,7 @@ threads - An ACE_Condition<> that enables blocking on state changes in the variable The class I create here will contain those three things. For the actual condition variable I've chosen an - integer. You could easily turn this clas into a template + integer. You could easily turn this class into a template parameterized on the condition variable's data type if 'int' isn't what you want. */ class Condition diff --git a/docs/tutorials/016/combine.shar b/docs/tutorials/016/combine.shar index 503f70b83be..9c5c9d8c6c0 100644 --- a/docs/tutorials/016/combine.shar +++ b/docs/tutorials/016/combine.shar @@ -3,8 +3,8 @@ # 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 1998-10-29 15:09 EST by <jcej@caldera.lads.com>. -# Source directory was `/scsiA/home/jcej/projects/ACE_wrappers/docs/tutorials/016'. +# Made on 1999-02-14 14:20 EST by <jcej@chiroptera.tragus.org>. +# Source directory was `/var/home/jcej/projects/ACE_wrappers/docs/tutorials/016'. # # Existing files will *not* be overwritten unless `-c' is specified. # @@ -12,12 +12,12 @@ # length mode name # ------ ---------- ------------------------------------------ # 422 -rw-rw-r-- hdr -# 50 -rw-rw-r-- bodies -# 789 -rw-rw-r-- page01.pre -# 1350 -rw-rw-r-- page02.pre +# 51 -rw-rw-r-- bodies +# 2917 -rw-rw-r-- page01.pre +# 1351 -rw-rw-r-- page02.pre # 248 -rw-rw-r-- page03.pre -# 309 -rw-rw-r-- page04.pre -# 605 -rw-rw-r-- page05.pre +# 310 -rw-rw-r-- page04.pre +# 606 -rw-rw-r-- page05.pre # save_IFS="${IFS}" IFS="${IFS}:" @@ -64,7 +64,7 @@ else fi rm -f 1231235999 $$.touch # -if mkdir _sh03957; then +if mkdir _sh31855; then $echo 'x -' 'creating lock directory' else $echo 'failed to create lock directory' @@ -124,12 +124,12 @@ SHAR_EOF && ( 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' -06c11389b22b88d88110d2338c4dbaaf bodies +53b96616ae101b38fd1e30b2ab8707a2 bodies SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`" - test 50 -eq "$shar_count" || - $echo 'bodies:' 'original size' '50,' 'current size' "$shar_count!" + test 51 -eq "$shar_count" || + $echo 'bodies:' 'original size' '51,' 'current size' "$shar_count!" fi fi # ============= page01.pre ============== @@ -153,20 +153,73 @@ In this tutorial, I'll create a wrapper class around the ACE_Condition and the assorted housekeeping items necessary to make it work. I'll use a simple integer as the condition variable but keep in mind that you can use any data type you want. +<P> +Kirthika's abstract: +<ul> +An ACE_Condition class is a synchronisation mechanism employed in +situations where one or more threads cannot access the shared resource +unless some 'condition' becomes true. The ACE_Condition is associated +with a Mutex-lock which is released before blocking internally in the +wait call. Once the blocked thread is signaled to wake up again it +internally re-acquires the lock before checking the condition. +Unless the condition is true and it has the lock, it cant go ahead. +Once the shared resource is freed, a signal is sent to the waiting +threads which can now contend for the lock and access the resource. +<P> +Pizza-delivery metaphor: (courtesy Dr.Schmidt) +<ul> +Pizza delivery boy -- thread<br> +keys to delivery van -- mutex-lock<br> +pizza ready for delivery -- condition<br> +</Ul> +Situation: <br> +<ul> +Five pizza delivery boys use the same van. While the van is +unavailable, the boys go to sleep. When the van returns and the keys +are returned, the current user of the van nudges the other sleeping boys +to wake up and fight for the keys. Once the keys are obtained and the +pizza +is ready and out of the kitchen, the boy with the pizza and the keys can +now deliver it. +</ul> +<P> +This tutorial makes use of a wrapper class around the ACE_Condition and +uses a integer value as the condition. The four kinds of condition +implemented +are: !=, >=, <=, == by using C++ operator overloading. Guards are used +within +the methods to make sure that the method is thread-safe. Once the thread +completes +its job, it broadcasts to the waiting on it. +<P> +An ACE_Task is used to stress test the various conditions. +A test object is created for each condition and the main thread waits +until the condition becomes true. For instance: <= condition: +Five threads are spwaned which in turn increment the condition +variable, which is initialised to 1 by 2. Remember that you are waiting +on +the <= condition. So once 3 threads have been thru it, the value becomes +6 +and the condition becomes true! +<P> +This simple example shows us how to program and use the Condition +variable for +synchronisation. +</ul> SHAR_EOF - $shar_touch -am 1029153198 'page01.pre' && + $shar_touch -am 0214140699 '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' -aa9f5774f5415d7a430891e9296bfab0 page01.pre +37032e8a180a426e2677f3c2848162bb page01.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`" - test 789 -eq "$shar_count" || - $echo 'page01.pre:' 'original size' '789,' 'current size' "$shar_count!" + test 2917 -eq "$shar_count" || + $echo 'page01.pre:' 'original size' '2917,' 'current size' "$shar_count!" fi fi # ============= page02.pre ============== @@ -228,12 +281,12 @@ SHAR_EOF && ( 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' -ccf4d7623038838df6249b5134827402 page02.pre +d3230a58558843154d2363ce940dbb9b page02.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`" - test 1350 -eq "$shar_count" || - $echo 'page02.pre:' 'original size' '1350,' 'current size' "$shar_count!" + test 1351 -eq "$shar_count" || + $echo 'page02.pre:' 'original size' '1351,' 'current size' "$shar_count!" fi fi # ============= page03.pre ============== @@ -283,12 +336,12 @@ SHAR_EOF && ( 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' -b6694ddc18814a64feeb56f46ffd7d17 page04.pre +a2b2c42216f88e006a18d37adcb31c1d page04.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`" - test 309 -eq "$shar_count" || - $echo 'page04.pre:' 'original size' '309,' 'current size' "$shar_count!" + test 310 -eq "$shar_count" || + $echo 'page04.pre:' 'original size' '310,' 'current size' "$shar_count!" fi fi # ============= page05.pre ============== @@ -320,13 +373,13 @@ SHAR_EOF && ( 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' -f63c4bfe37b1fe5785a6af9b204cb0bf page05.pre +3926547773016bf56d809fae9170625e page05.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`" - test 605 -eq "$shar_count" || - $echo 'page05.pre:' 'original size' '605,' 'current size' "$shar_count!" + test 606 -eq "$shar_count" || + $echo 'page05.pre:' 'original size' '606,' 'current size' "$shar_count!" fi fi -rm -fr _sh03957 +rm -fr _sh31855 exit 0 diff --git a/docs/tutorials/016/condition.cpp b/docs/tutorials/016/condition.cpp index 5ec772a4a7f..d489ee6a355 100644 --- a/docs/tutorials/016/condition.cpp +++ b/docs/tutorials/016/condition.cpp @@ -12,7 +12,7 @@ class Test : public ACE_Task<ACE_NULL_SYNCH> { public: // Construct the condition variable with an initial value. - Test( Condition::value_t _value ); + Test( int _max_threads, Condition::value_t _value ); ~Test(void); // Open the Task with enough threads to make a useful test. @@ -24,12 +24,13 @@ protected: // Override this method to modify the Condition in some way. virtual void modify(void) = 0; + // Override this to test the Condition in some way. virtual void test(void) = 0; // How many threads to use in the test. This is also used in the // modify() and test() methods of the derivatives. - static const int max_threads_; + int max_threads_; // We want to sleep for a random amount of time to simulate // work. The seed is necessary for proper random number generation. @@ -39,12 +40,9 @@ protected: Condition condition_; }; -// Set the number of threads. -const int Test::max_threads_ = 5; - // Initialize the condition variable. -Test::Test( Condition::value_t _value ) - : condition_(_value) +Test::Test( int _max_threads, Condition::value_t _value ) + : max_threads_(_max_threads), condition_(_value) { ; } @@ -99,8 +97,8 @@ class Test_ne : public Test { public: // Initialize the condition variable to zero since we're counting up. - Test_ne(void) - : Test(0) + Test_ne( int _max_threads ) + : Test(_max_threads,0) { ACE_DEBUG ((LM_INFO, "\n(%P|%t|%T)\tTesting condition_ != %d\n", max_threads_)); } @@ -129,8 +127,8 @@ public: // For max_threads_ == 5, we will start the condition variable at // the value 9. When the "last" thread decrements it, the value // will be 4 which satisfies the condition. - Test_ge(void) - : Test(max_threads_*2-1) + Test_ge( int _max_threads ) + : Test(_max_threads,_max_threads*2-1) { ACE_DEBUG ((LM_INFO, "\n(%P|%t|%T)\tTesting condition_ >= %d\n", max_threads_)); } @@ -159,8 +157,8 @@ public: // I'm starting the value at 1 so that if we increment by one in // each thread, the "last" thread (of 5) will set the value to // 6. Since I actually increment by 2, we could start somewhat lower. - Test_le(void) - : Test(1) + Test_le( int _max_threads ) + : Test( _max_threads, 1 ) { ACE_DEBUG ((LM_INFO, "\n(%P|%t|%T)\tTesting condition_ <= %d\n", max_threads_)); } @@ -188,8 +186,8 @@ class Test_fo : public Test public: // We'll be using operator*=(int) to increment the condition // variable, so we need to start with a non-zero value. - Test_fo(void) - : Test(1) + Test_fo( int _max_threads ) + : Test( _max_threads, 1 ) { ACE_DEBUG ((LM_INFO, "\n(%P|%t|%T)\tTesting condition_ == FunctionObject\n" )); } @@ -209,6 +207,8 @@ public: public: // When this returns non-zero, the condition test operator // will unblock in each thread. + // Note that 32 was chosen because 2**5 == 32. That is, the + // fifth thread will modify() the value to 32. int operator() ( Condition::value_t _value ) { return _value == 32; @@ -229,19 +229,19 @@ public: */ int main(int, char **) { - Test_ne test_ne; + Test_ne test_ne(5); test_ne.open(); test_ne.wait(); - Test_ge test_ge; + Test_ge test_ge(5); test_ge.open(); test_ge.wait(); - Test_le test_le; + Test_le test_le(5); test_le.open(); test_le.wait(); - Test_fo test_fo; + Test_fo test_fo(5); test_fo.open(); test_fo.wait(); diff --git a/docs/tutorials/016/page01.html b/docs/tutorials/016/page01.html index 057ca7142d9..8781d692e14 100644 --- a/docs/tutorials/016/page01.html +++ b/docs/tutorials/016/page01.html @@ -27,5 +27,58 @@ In this tutorial, I'll create a wrapper class around the ACE_Condition and the assorted housekeeping items necessary to make it work. I'll use a simple integer as the condition variable but keep in mind that you can use any data type you want. +<P> +Kirthika's abstract: +<ul> +An ACE_Condition class is a synchronisation mechanism employed in +situations where one or more threads cannot access the shared resource +unless some 'condition' becomes true. The ACE_Condition is associated +with a Mutex-lock which is released before blocking internally in the +wait call. Once the blocked thread is signaled to wake up again it +internally re-acquires the lock before checking the condition. +Unless the condition is true and it has the lock, it cant go ahead. +Once the shared resource is freed, a signal is sent to the waiting +threads which can now contend for the lock and access the resource. +<P> +Pizza-delivery metaphor: (courtesy Dr.Schmidt) +<ul> +Pizza delivery boy -- thread<br> +keys to delivery van -- mutex-lock<br> +pizza ready for delivery -- condition<br> +</Ul> +Situation: <br> +<ul> +Five pizza delivery boys use the same van. While the van is +unavailable, the boys go to sleep. When the van returns and the keys +are returned, the current user of the van nudges the other sleeping boys +to wake up and fight for the keys. Once the keys are obtained and the +pizza +is ready and out of the kitchen, the boy with the pizza and the keys can +now deliver it. +</ul> +<P> +This tutorial makes use of a wrapper class around the ACE_Condition and +uses a integer value as the condition. The four kinds of condition +implemented +are: !=, >=, <=, == by using C++ operator overloading. Guards are used +within +the methods to make sure that the method is thread-safe. Once the thread +completes +its job, it broadcasts to the waiting on it. +<P> +An ACE_Task is used to stress test the various conditions. +A test object is created for each condition and the main thread waits +until the condition becomes true. For instance: <= condition: +Five threads are spwaned which in turn increment the condition +variable, which is initialised to 1 by 2. Remember that you are waiting +on +the <= condition. So once 3 threads have been thru it, the value becomes +6 +and the condition becomes true! +<P> +This simple example shows us how to program and use the Condition +variable for +synchronisation. +</ul> <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/016/page02.html b/docs/tutorials/016/page02.html index 70e58f57e3f..bda581108e5 100644 --- a/docs/tutorials/016/page02.html +++ b/docs/tutorials/016/page02.html @@ -72,7 +72,7 @@ condition to occur. threads - An ACE_Condition<> that enables blocking on state changes in the variable The class I create here will contain those three things. For the actual condition variable I've chosen an - integer. You could easily turn this clas into a template + integer. You could easily turn this class into a template parameterized on the condition variable's data type if 'int' isn't what you want. */</font> class Condition diff --git a/docs/tutorials/016/page04.html b/docs/tutorials/016/page04.html index b94fe2e48af..654790d6594 100644 --- a/docs/tutorials/016/page04.html +++ b/docs/tutorials/016/page04.html @@ -33,7 +33,7 @@ class Test : public ACE_Task<ACE_NULL_SYNCH> { public: <font color=red>// Construct the condition variable with an initial value.</font> - Test( <font color=#008888>Condition::value_t</font> _value ); + Test( int _max_threads, <font color=#008888>Condition::value_t</font> _value ); ~Test(void); <font color=red>// Open the Task with enough threads to make a useful test.</font> @@ -45,12 +45,13 @@ protected: <font color=red>// Override this method to modify the Condition in some way.</font> virtual void modify(void) = 0; + <font color=red>// Override this to test the Condition in some way.</font> virtual void test(void) = 0; <font color=red>// How many threads to use in the test. This is also used in the</font> <font color=red>// modify() and test() methods of the derivatives.</font> - static const int max_threads_; + int max_threads_; <font color=red>// We want to sleep for a random amount of time to simulate</font> <font color=red>// work. The seed is necessary for proper random number generation.</font> @@ -60,12 +61,9 @@ protected: Condition condition_; }; -<font color=red>// Set the number of threads.</font> -const int <font color=#008888>Test::max_threads_</font> = 5; - <font color=red>// Initialize the condition variable.</font> -<font color=#008888>Test::Test</font>( Condition::value_t _value ) - : condition_(_value) +<font color=#008888>Test::Test</font>( int _max_threads, Condition::value_t _value ) + : max_threads_(_max_threads), condition_(_value) { ; } @@ -120,8 +118,8 @@ class Test_ne : public Test { public: <font color=red>// Initialize the condition variable to zero since we're counting up.</font> - Test_ne(void) - : Test(0) + Test_ne( int _max_threads ) + : Test(_max_threads,0) { ACE_DEBUG ((LM_INFO, "<font color=green>\n(%P|%t|%T)\tTesting condition_ != %d\n</font>", max_threads_)); } @@ -150,8 +148,8 @@ public: <font color=red>// For max_threads_ == 5, we will start the condition variable at </font> <font color=red>// the value 9. When the "<font color=green>last</font>" thread decrements it, the value</font> <font color=red>// will be 4 which satisfies the condition.</font> - Test_ge(void) - : Test(max_threads_*2-1) + Test_ge( int _max_threads ) + : Test(_max_threads,_max_threads*2-1) { ACE_DEBUG ((LM_INFO, "<font color=green>\n(%P|%t|%T)\tTesting condition_ >= %d\n</font>", max_threads_)); } @@ -180,8 +178,8 @@ public: <font color=red>// I'm starting the value at 1 so that if we increment by one in</font> <font color=red>// each thread, the "<font color=green>last</font>" thread (of 5) will set the value to</font> <font color=red>// 6. Since I actually increment by 2, we could start somewhat lower.</font> - Test_le(void) - : Test(1) + Test_le( int _max_threads ) + : Test( _max_threads, 1 ) { ACE_DEBUG ((LM_INFO, "<font color=green>\n(%P|%t|%T)\tTesting condition_ <= %d\n</font>", max_threads_)); } @@ -209,8 +207,8 @@ class Test_fo : public Test public: <font color=red>// We'll be using operator*=(int) to increment the condition</font> <font color=red>// variable, so we need to start with a non-zero value.</font> - Test_fo(void) - : Test(1) + Test_fo( int _max_threads ) + : Test( _max_threads, 1 ) { ACE_DEBUG ((LM_INFO, "<font color=green>\n(%P|%t|%T)\tTesting condition_ == FunctionObject\n</font>" )); } @@ -230,6 +228,8 @@ public: public: <font color=red>// When this returns non-zero, the condition test operator</font> <font color=red>// will unblock in each thread.</font> + <font color=red>// Note that 32 was chosen because 2**5 == 32. That is, the</font> + <font color=red>// fifth thread will modify() the value to 32.</font> int operator() ( <font color=#008888>Condition::value_t</font> _value ) { return _value == 32; @@ -250,19 +250,19 @@ public: */</font> int main(int, char **) { - Test_ne test_ne; + Test_ne test_ne(5); test_ne.open(); test_ne.wait(); - Test_ge test_ge; + Test_ge test_ge(5); test_ge.open(); test_ge.wait(); - Test_le test_le; + Test_le test_le(5); test_le.open(); test_le.wait(); - Test_fo test_fo; + Test_fo test_fo(5); test_fo.open(); test_fo.wait(); diff --git a/docs/tutorials/017/combine.shar b/docs/tutorials/017/combine.shar index 7e826ed7928..ff6f7ef7d2d 100644 --- a/docs/tutorials/017/combine.shar +++ b/docs/tutorials/017/combine.shar @@ -3,8 +3,8 @@ # 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 1998-11-10 14:42 EST by <jcej@caldera.lads.com>. -# Source directory was `/scsiA/home/jcej/projects/ACE_wrappers/docs/tutorials/017'. +# Made on 1999-02-14 14:25 EST by <jcej@chiroptera.tragus.org>. +# Source directory was `/var/home/jcej/projects/ACE_wrappers/docs/tutorials/017'. # # Existing files will *not* be overwritten unless `-c' is specified. # @@ -12,11 +12,11 @@ # length mode name # ------ ---------- ------------------------------------------ # 422 -rw-rw-r-- hdr -# 44 -rw-rw-r-- bodies -# 843 -rw-rw-r-- page01.pre -# 419 -rw-rw-r-- page02.pre +# 45 -rw-rw-r-- bodies +# 1397 -rw-rw-r-- page01.pre +# 420 -rw-rw-r-- page02.pre # 739 -rw-rw-r-- page03.pre -# 478 -rw-rw-r-- page04.pre +# 479 -rw-rw-r-- page04.pre # 375 -rw-rw-r-- page05.pre # save_IFS="${IFS}" @@ -64,7 +64,7 @@ else fi rm -f 1231235999 $$.touch # -if mkdir _sh01874; then +if mkdir _sh32003; then $echo 'x -' 'creating lock directory' else $echo 'failed to create lock directory' @@ -124,12 +124,12 @@ SHAR_EOF && ( 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' -1b7c57aab2c61f845219723b8558bea6 bodies +4924294a77d6ba78dcf667e92c341b4f bodies SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`" - test 44 -eq "$shar_count" || - $echo 'bodies:' 'original size' '44,' 'current size' "$shar_count!" + test 45 -eq "$shar_count" || + $echo 'bodies:' 'original size' '45,' 'current size' "$shar_count!" fi fi # ============= page01.pre ============== @@ -156,20 +156,36 @@ continuing. In this tutorial I'll create a simple wrapper for the ACE_Barrier. In reality, the ACE_Barrier is so easy that a wrapper isn't really needed. I created the wrapper anyway though just because I wanted to. +<P> +Kirthika's abstract: +<ul> +The ACE_Barrier class is used for collective thread syncronisation. All +the threads block at the barrier and advance only after everyone is at +the +barrier. A thread blocks by calling the wait() method and stays until +all the other threads invoke wait() one-by-one at the barrier and then +all +move ahead. +Here, an abstract barrier class is created which incorporates the +ACE_Barrier +mechanism and is used in a test case of an ACE_Task with 10 and 5 +threads respectively +which illustrate the use of the barrier pattern. +</ul> SHAR_EOF - $shar_touch -am 1110144198 'page01.pre' && + $shar_touch -am 0214142599 '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' -30840e2b3e8bf84d94abb9177bffbbec page01.pre +2c9cb9ca7f82997142a59a9324d5fe17 page01.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`" - test 843 -eq "$shar_count" || - $echo 'page01.pre:' 'original size' '843,' 'current size' "$shar_count!" + test 1397 -eq "$shar_count" || + $echo 'page01.pre:' 'original size' '1397,' 'current size' "$shar_count!" fi fi # ============= page02.pre ============== @@ -195,12 +211,12 @@ SHAR_EOF && ( 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' -72dd8d286e36d8911945824bf2c91cc3 page02.pre +9e2b4b85abf1bff15b94b6d20bc20f91 page02.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`" - test 419 -eq "$shar_count" || - $echo 'page02.pre:' 'original size' '419,' 'current size' "$shar_count!" + test 420 -eq "$shar_count" || + $echo 'page02.pre:' 'original size' '420,' 'current size' "$shar_count!" fi fi # ============= page03.pre ============== @@ -260,12 +276,12 @@ SHAR_EOF && ( 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' -bed05089cb64c075cceec277e2a7da5f page04.pre +0c46b51370a57179cea56ef57fd0b1f4 page04.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`" - test 478 -eq "$shar_count" || - $echo 'page04.pre:' 'original size' '478,' 'current size' "$shar_count!" + test 479 -eq "$shar_count" || + $echo 'page04.pre:' 'original size' '479,' 'current size' "$shar_count!" fi fi # ============= page05.pre ============== @@ -300,5 +316,5 @@ SHAR_EOF $echo 'page05.pre:' 'original size' '375,' 'current size' "$shar_count!" fi fi -rm -fr _sh01874 +rm -fr _sh32003 exit 0 diff --git a/docs/tutorials/017/page01.html b/docs/tutorials/017/page01.html index 5486ecbf66a..25d4c94ae02 100644 --- a/docs/tutorials/017/page01.html +++ b/docs/tutorials/017/page01.html @@ -30,5 +30,21 @@ continuing. In this tutorial I'll create a simple wrapper for the ACE_Barrier. In reality, the ACE_Barrier is so easy that a wrapper isn't really needed. I created the wrapper anyway though just because I wanted to. +<P> +Kirthika's abstract: +<ul> +The ACE_Barrier class is used for collective thread syncronisation. All +the threads block at the barrier and advance only after everyone is at +the +barrier. A thread blocks by calling the wait() method and stays until +all the other threads invoke wait() one-by-one at the barrier and then +all +move ahead. +Here, an abstract barrier class is created which incorporates the +ACE_Barrier +mechanism and is used in a test case of an ACE_Task with 10 and 5 +threads respectively +which illustrate the use of the barrier pattern. +</ul> <P><HR WIDTH="100%"> <CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page02.html">Continue This Tutorial</A>]</CENTER> |