This topic explains the operations that can be performed using message queue.
A global queue is created by calling CreateGlobal()
on
a handle object, while a local queue is created by calling CreateLocal()
.
A
global queue is opened by calling OpenGlobal()
on a handle
object, passing a queue name.
All the memory used by the queue is allocated when the queue is created, so it is possible for the call that creates a queue to fail with out of memory. The queue is deleted when the last open handle on it is closed.
Creating a global named queue
_LIT(KGLobalName, "GlobalMessageQueue"); const TInt KNumberOfSlots = 5; const TInt KMessageLength = 16; RMsgQueueBase queue; TInt ret = queue.CreateGlobal(KGLobalName, KNumberOfSlots, KMessageLength, EOwnerProcess);
This code fragment creates a global named message
queue called GlobalMessageQueue
with 5 slots, each capable
of holding a message of size 16 bytes. Note that we have explicitly used RMsgQueueBase
. In
practice, you would use the template class RMsgQueue
.
For example:
class TMyClass { public: TInt iA; TInt iB; TInt iC; TInt iD; } _LIT(KGLobalName, "GlobalMessageQueue"); const TInt KNumberOfSlots = 5; RMsgQueue<TMyClass> queue; TInt ret = queue.CreateGlobal(KGLobalName, KNumberOfSlots, EOwnerProcess);
The length of the message is the length of the templated class, which in this example is also 16.
Creating a local message queue
const TInt KNumberOfSlots = 2; RMsgQueueBase queue; TInt ret = queue.CreateLocal(KNumberOfSlots, RMsgQueueBase::KMaxLength);
This creates a local queue with 2 message slots that
have the maximum possible message size. In practice, you would use
the template class RMsgQueue
rather than the base class RMsgQueueBase
.
Opening a named global queue
_LIT(KGLobalName, "GlobalMessageQueue"); RMsgQueueBase queue; TInt messageSize = 0; TInt ret = queue.OpenGlobal(KGLobalName1); If (ret == KErrNone) { messageSize = queue.MessageSize(); }
This opens the global named message queue called GlobalMessageQueue
.
The message size used within this queue is queried by calling MessageSize()
.
If the queue does not exist OpenGlobal()
returns KErrNotFound
.
Note
that using an illegal message size when writing to, or reading from, a queue
is a programming error. In practice, you would use the templated class RMsgQueue
rather
than the base class RMsgQueueBase
to avoid this problem.
A message is sent to a message queue by calling Send()
or SendBlocking()
on
the message queue handle. Send()
returns the error code KErrOverflow if
the queue is full, SendBlocking()
waits until there is space
in the queue.
The following example creates a global named queue, and
sends 2 integer to values to it. The first call to Send()
returns
an error if the queue is full, the call to SendBlocking()
waits
until there is space in the queue. Although the example code uses the base
class RMsgQueueBase
, in practice you would use the
templated class RMsgQueue
, to avoid the risk of passing
an invalid length, message size, or an invalid data pointer.
_LIT(KGLobalName, "GlobalMessageQueue"); RMsgQueueBase mqueue; TInt ret = mqueue.CreateGlobal(KGLobalName1, 1, sizeof (TInt)); if (ret == KErrNone) { TInt src = 45; ret = mqueue.Send(&src, sizeof (TInt)); TBool full = (ret == KErrOverflow); //blocking send src = 32; mqueue.SendBlocking(&src, sizeof(TInt)); mqueue.Close(); }
A message is received from a message queue
by calling Receive()
or ReceiveBlocking()
on
the message queue handle. Receive()
returns the error code KErrUnderflow if
the queue is empty, ReceiveBlocking()
waits until there is
data in the queue.
The following example opens a global named queue
and receives 2 integer values from it. The first call to Receive()
returns
an error if the queue is empty, the call to ReceiveBlocking()
waits
until there is data available in the queue. Note also that using the base
class RMsgQueueBase
rather than the templated class RMsgQueue
risks
raising panics if the length specified is not the same as the message size
specified when the queue was originally created, or if the pointer to the
receive buffer is not a valid address.
_LIT(KGLobalName, "GlobalMessageQueue"); RMsgQueueBase mqueue; TInt ret = mqueue.OpenGlobal(KGLobalName1); if (ret == KErrNone) { TInt data; ret = mqueue.Receive(&data, sizeof (TInt)); TBool empty = (ret == KErrUnderflow); //blocking receive mqueue.ReceiveBlocking(&data, sizeof(TInt)); mqueue.Close(); }
It is possible to be notified:
when a queue has messages,
by calling NotifyDataAvailable()
on the base class RMsgQueueBase
when a queue has space
for more messages, by calling NotifySpaceAvailable()
on the
base class RMsgQueueBase
.
Note that the calling NotifyDataAvailable()
when
such a request is still outstanding or calling NotifySpaceAvailable()
when
such a request is already outstanding, results in the calling thread being
panicked
Notification requests can be cancelled by calling CancelDataAvailable()
or CancelDataAvailable()
respectively.
TRequestStatus stat; mqueue.NotifyDataAvailable(stat); mqueue.CancelDataAvailable(); User::WaitForRequest(stat);
The size of the message slot can be queried by calling MessageSize()
on
the handle. This is useful when a queue is opened, as the calling thread is
panicked if the size is out of range on a Send()
or if the
size is not exact on a Receive().
The size of the message is the size of
the type, and has the same restrictions as the base class, namely it must
be greater than 0, a multiple of 4 bytes and not greater than RMsgQueueBase::KMaxLength
.
class TTemplateTestData { public: TTemplateTestData(); TTemplateTestData(TInt a, TUint b, TUint8 c, TBool d, TInt e); public: TInt first; TUint second; TUint8 third; TBool fourth; TInt fifth; }; { .... RMsgQueue<TTemplateTestData> templateQueue; TTemplateTestData ch(1,2,3,ETrue,4); TTemplateTestData ch2; TTemplateTestData ch3; templateQueue.CreateLocal(12); templateQueue.Send(ch); templateQueue.Receive(ch2); .... templateQueue.Close(); ... }
Note, the size of the type (i.e. the size of the message) must be a multiple of 4 bytes.