1<HTML> 2<!-- $Id: BMessageQueueUseCases.html 10 2002-07-09 12:24:59Z ejakowatz $ --> 3<HEAD> 4<TITLE>BMessageQueue Use Cases and Implementation Details</TITLE> 5</HEAD> 6 7<BODY BGCOLOR="white" LINK="#000067" VLINK="#000067" ALINK="#0000FF"> 8 9<FONT FACE="Verdana,Arial,Helvetica,sans-serif" SIZE="-1"> 10 11<H1>BMessageQueue Use Cases and Implementation Details:</H1> 12 13<P>This document describes the BMessageQueue interface and some basics of how it is implemented. 14The document has the following sections:</P> 15 16<OL> 17<LI><A HREF="#interface">BMessageQueue Interface</A></LI> 18<LI><A HREF="#usecases">BMessageQueue Use Cases</A></LI> 19<LI><A HREF="#implement">BMessageQueue Implementation</A></LI> 20</OL> 21 22<A NAME="interface"></A><H2>BMessageQueue Interface:</H2> 23 24<P>The BMessageQueue class is a simple class for managing a queue of BMessages. The best 25source of information for the BMessageQueue interface can be found 26<A HREF="file:///boot/beos/documentation/Be%20Book/The%20Application%20Kit/MessageQueue.html">here in the Be Book</A>. 27</P> 28 29<A NAME="usecases"></A><H2>BMessageQueue Use Cases:</H2> 30 31<P>The following use cases cover the BMessageQueue functionality:</P> 32 33<OL> 34<LI><P><B>Construction:</B> A BMessageQueue does not take any arguments when it is constructed. 35After construction, the queue is empty.</P></LI> 36 37<LI><P><B>Destruction:</B> When a BMessageQueue is deconstructed, all BMessages on the queue are 38deleted. This implies that all BMessages added to a BMessageQueue must be allocated on the heap 39with the new operation. The BMessageQueue is locked before performing the delete to ensure 40that the queue doesn't change while it is being deleted. The lock is never released from the 41destructor to ensure that any AddMessage() or other members blocking for the lock never 42succeed in getting the lock. They will fail once the BMessageQueue is completely deleted.</P></LI> 43 44<LI><P><B>Add Message 1:</B> When AddMessage() is used to put a BMessage on the queue, the 45BMessageQueue takes ownership of the BMessage. The BMessage should be created on the heap but 46there is no checking to ensure that has happened. The BMessageQueue records the order in 47which the BMessages are added to the queue.</P></LI> 48 49<LI><P><B>Add Message 2:</B> No check is performed to see if the BMessage is already part of that 50BMessageQueue or any other when AddMessage() is used to put a BMessage on a queue. An attempt to 51add a BMessage to a BMessageQueue which already has that same BMessage in it (where equality is 52based on the address of the BMessage) will corrupt the queue. An attempt to add a BMessage to a 53BMessageQueue when that BMessage is already in another BMessageQueue will corrupt the original 54BMessageQueue. It is up to the caller of AddMessage() to use RemoveMessage() to prevent 55queue corruption.</P></LI> 56 57<LI><P><B>Add Message 3:</B> BMessage's can be added using AddMessage() from multiple threads 58at the same time with no risk of queue corruption. Similarly, RemoveMessage() or NextMessage() 59can be executing from another thread while an AddMessage() is started without corrupting the queue. 60An AddMessage() attempt will block if another thread has used the Lock() member to lock the 61BMessageQueue.</P></LI> 62 63<LI><P><B>Remove Message 1:</B> The RemoveMessage() member takes a BMessage pointer. The 64BMessageQueue is searched for this BMessage pointer. If that pointer is in the queue, then it 65is removed from the queue. The BMessage is not deleted (note the BeBook implies it is but in 66fact it is not). If the BMessage pointer is not on this BMessageQueue, this call has no affect. 67After this call completes successfully, it is as though AddMessage() was never called for 68this BMessage pointer.</P></LI> 69 70<LI><P><B>Remove Message 2:</B> BMessage's can be removed using RemoveMessage() from multiple 71threads at the same time with no risk of queue corruption. Similarly, AddMessage() or 72NextMessage() can be executing from another thread while a RemoveMessage() is started without 73corrupting the queue. A RemoveMessage() attempt will block if another thread has used the Lock() 74member to lock the BMessageQueue.</P></LI> 75 76<LI><P><B>Count Messages:</B> The CountMessages() member function returns the number of BMessage's 77in the BMessageQueue. If there are no messages on the queue (an example of this situation is just 78after construction), the member returns 0. Note, it is possible for the count to become corrupted 79if the situation in Add Message 2 occurs.</P></LI> 80 81<LI><P><B>Is Empty:</B> The IsEmpty() member function returns true if there are no BMessages on the 82BMessageQueue. If there are one or more BMessages on the BMessageQueue, it returns false.</P></LI> 83 84<LI><P><B>Find Message 1:</B> The FindMessage() member function is overloaded. If the member 85function takes a single int32 argument, it is used to return the BMessage on the queue at a 86particular index as indicated by the argument. The first message is at index 0, the second 87at index 1 etc. If no message is at that index, NULL is returned.</P></LI> 88 89<LI><P><B>Find Message 2:</B> The other FindMessage() member function takes a single uint32 90argument and an optional int32 argument. The first mandatory argument specifies the "what" code 91for the BMessage being searched for. The second optional argument specifies what occurance of 92that "what" code in a BMessage on the queue should be returned. If the second argument is not 93provided, it is assumed to be 0. If the second argument is 0, the first BMessage that has the 94what code provided is returned. If the second argument is 1, the second BMessage that has the 95what code provided is returned, etc. If no match is found, NULL is returned.</P></LI> 96 97<LI><P><B>Lock 1:</B> The Lock() member function blocks until this thread can acquire exclusive 98access to the BMessageQueue. Only one thread can hold the lock at any one time. A thread can 99acquire the Lock() multiple times but release it the same number of times. While a thread holds 100the lock, other threads will not be able to perform AddMessage(), RemoveMessage() or NextMessage(). 101Any threads attempting to do so will block until the BMessageQueue is unlocked.</P></LI> 102 103<LI><P><B>Lock 2:</B> The Lock() member function returns true if the lock has successfully been 104acquired. It will return false if an unrecoverable error has occurred. An example of such an 105error would be deleting the BMessageQueue.</P></LI> 106 107<LI><P><B>Unlock:</B> The Unlock() member function releases a lock on the BMessageQueue. If the 108thread no longer holds any locks on the BMessageQueue, other threads are free to acquire the 109BMessageQueue lock or call member functions like AddMessage(), RemoveMessage(), NextMessage() or 110delete the BMessageQueue.</P></LI> 111 112<LI><P><B>Next Message 1:</B> The NextMessage() member function removes the BMessage which is the 113oldest on the queue. It returns that BMessage to the caller. After the call completes, the 114BMessage is no longer on the queue and the next oldest BMessage is at the front of the queue 115(ie next to be returned by NextMessage()).</P></LI> 116 117<LI><P><B>Next Message 2:</B> BMessage's can be removed using NextMessage() from multiple 118threads at the same time with no risk of queue corruption. Similarly, AddMessage() or 119RemoveMessage() can be executing from another thread while a NextMessage() is started without 120corrupting the queue. A NextMessage() attempt will block if another thread has used the Lock() 121member to lock the BMessageQueue.</P></LI> 122 123</OL> 124 125<A NAME="implement"></A><H2>BMessageQueue Implementation:</H2> 126 127<P>Internally, the BMessageQueue uses a BLocker to ensure that member functions like AddMessage(), 128RemoveMessage() and NextMessage() do not corrupt the queue when used from multiple threads. The 129same BLocker is used to implemented the Lock() and Unlock() members.</P> 130 131<P>Testing with a debugger shows that the queue is implemented using a "link" pointer in the 132BMessage class itself. Each BMessage is also a singly linked list which represents the queue. 133All the BMessageQueue needs is a pointer to the BMessage which starts the list. For performance 134reasons, it is worth maintaining a pointer to the BMessage at the end of the list and the count 135of the number of elements in the list. If these are not maintained, adding an element to the 136list will get slower as the number of elements grows and the cost to determine the number of 137elements in the list will be high.</P> 138 139<P>Because the BMessageQueue uses the link pointer which is a private part of the BMessage class, 140the BMessageQueue must be a friend class of BMessage. Checking the headers, this is in fact the 141case in Be's implementation. Although friendship in classes can cause some pretty serious long 142term headaches if abused (and I am not convinced that this is an abuse), the OpenBeOS 143implementation will follow the same implementation for now.</P> 144 145 146</BODY> 147</HTML> 148