I l @ ve RuBoard |
MotivationMany networked applications require a means to manipulate messages efficiently [SS93]. Standard message management operations include
To improve efficiency, these operations must minimize the overhead of dynamic memory management and avoid unnecessary data copying, which is why ACE provides the ACE_Message_Block class. Class CapabilitiesThe ACE_Message_Block class enables efficient manipulation of fixed- and variable- sized messages. ACE_Message_Block implements the Composite pattern [GHJV95] and provides the following capabilities:
The interface of the ACE_Message_Block class is shown in Figure 4.1. Its design is modeled loosely on the System V STREAMS [Rag93] message buffering mechanism, and it supports two kinds of messages:
Figure 4.1. The ACE_Message_Block Class Diagram
Figure 4.2. Two Kinds of ACE_Message_Block
The key methods of ACE_Message_Block are outlined in the following table:
Each ACE_Message_Block contains a pointer to a reference-counted ACE_Data_Block , which in turn points to the actual data payload, as shown in Figure 4.2 (1). Note how the rd_ptr() and wr_ptr() point to the beginning and end of the active portion of the data payload, respectively. Figure 4.2 (2) shows how the ACE_Message_Block::duplicate() method can be used to make a "shallow copy" of a message. This allows them to share the same data flexibly and efficiently by minimizing memory allocation and copying overhead. Since the message block itself is copied , the rd_ptr() s and wr_ptr() s can point to different parts of the same shared data payload. ExampleThe following program reads all data from standard input into a singly linked list of dynamically allocated ACE_Message_Blocks that are chained together by their continuation pointers. It then prints the contents of all the chained message blocks to the standard output and releases their dynamically allocated memory. #include "ace/OS.h" #include "ace/Message_Block.h" int main (int argc, char *argv[]) { ACE_Message_Block *head = new ACE_Message_Block (BUFSIZ); ACE_Message_Block *mblk = head; for (;;) { ssize_t nbytes = ACE::read_n (ACE_STDIN, mblk->wr_ptr (), mblk->size () ) ; if (nbytes <= 0) break; // Break out at EOF or error. // Advance the write pointer to the end of the buffer. mblk->wr_ptr (nbytes); // Allocate message block and chain it at the end of list. mblk->cont (new ACE_Message_Block (BUFSIZ)); mblk = mblk->cont (); } // Print the contents of the list to the standard output. for (mblk = head; mblk != 0; mblk = mblk->cont ()) ACE::write_n (ACE_STDOUT, mblk->rd_ptr (), mblk->length ()); head->release (); // This releases all the memory in the chain. return 0; } The for loop that prints the contents of the list to the standard output can be replaced by a single call to ACE::write_n (head) . This method prints out all the message blocks chained through their cont () pointers using a highly efficient gather-write operation. A similar optimization is used in the Logging_Handler::write_log_record() method on page 90. We use the ACE::read_n() and ACE::write_n() methods rather than the C++ iostreams mechanism since not all OS platforms that ACE runs on support C++ iostreams adequately. It's possible to substitute cin and cout on platforms that do support them properly. They may incur additional data copying due to internal buffering, however, and can't take advantage of the gather-write optimization described in the preceding paragraph. |
I l @ ve RuBoard |