#程序员##IT教育##软件开发##.net##软件工程师#
介绍
我的目标不是对消息队列做详尽的解释,而是为读者提供足够的信息来了解这个概念并继续下去。
先决条件
原生函数和结构
下面列出了用于其中一些功能的结构:
什么是消息队列
消息队列可以特定于某个进程,也可以在进程之间共享。在任何一种情况下,消息队列的句柄都允许对队列进行只读或只写访问。您不能使用同一个句柄同时读取和写入消息队列。如果您已经拥有消息队列的句柄,则可以创建额外的句柄来读取或写入关联的队列。这对于未命名的队列尤其重要。
创建和打开消息队列
通过本机函数创建或打开消息队列CreateMsgQueue。与上一篇文章中的同步对象一样,必须为消息队列分配一个名称才能在进程之间共享。如果多个进程创建同名的消息队列,那么每个进程都会收到同一个消息队列的句柄。创建消息队列的调用必须传递一个MSGQUEOPTIONS结构来指定消息队列中的最大项目数、队列中每条消息的最大大小以及请求的是只读句柄还是只写句柄.
如果您的消息队列仅用于将信息移动到同一进程中的线程(在这种情况下,消息队列可能没有名称),您将需要使用您创建的第一个消息队列的句柄来创建另一个句柄使用OpenMsgQueue附加到同一个队列。如果在创建新消息句柄时没有此函数,则无法指定正在创建的句柄应附加到已存在的先前队列。
消息队列由操作系统创建,是一种系统资源。当您不再需要它时,您必须确保释放您对消息队列的句柄。您可以使用CloseMsgQueue释放消息队列句柄。
基类
与系统事件一样,信 量和互斥消息队列是可等待的,可以选择具有名称,并通过必须手动清除的句柄绑定到资源。上一篇文章中的SyncBase类已经设计为保存系统资源的句柄。类的布局如下图所示:
C#
与系统事件一样,当代码在队列中等待时,它将被阻塞,直到队列处于信 状态。对于队列的只读句柄,信 状态意味着有数据准备好从队列中读取。对于只写句柄,信 状态意味着队列中有足够的空间容纳更多消息。一旦队列已满,句柄就不再发出信 。因此Wait基类中定义的方法无需修改即可使用。
必须定义构造函数并调用CreateMsgQueue. 调用返回的句柄将保存在 member 中_hSyncHandle。
构造函数
虽然有多个消息队列构造函数,但它们都调用两个基本构造函数之一。本机函数CreateMsgQueue在构造函数中使用,它需要MSGQUEUEOPTIONS创建参数的参数。我已经实现了托管类MsgQueueOptions以反映结构,并将此类实例的创建和启动包装在GetMessageQueueOptions方法中。我现在允许调用者有一个消息队列设置。它是MsgQueueOptions的 dwFlags成员。可以通过此标志设置的选项是MSGQUEUE_NOPRECOMMIT和MSGQUEUE_ALLOW_BROKEN。MSGQUEUE_NOPRECOMMIT这会阻止系统预先分配消息队列所需的内存,并根据需要分配内存。MSGQUEUE_ALLOW_BROKEN用于允许写入队列可用,即使另一端没有读取队列。如果未指定此选项,并且如果在读取器连接到队列之前尝试写入队列,则句柄将立即变得不可用(因此,我永远不会省略该标志。如果创建读取器或 writer 导致创建队列,则GetLastWin32Error返回SUCCESS(数值 0),否则返回,ERROR_ALREADY_EXISTS只要返回非零句柄CreateMsgQueue,则调用成功。GetLastWin32Error()队列的句柄刚刚创建。下面是基本构造函数的代码:
C#
另一个重要的构造函数是使用另一个队列端点作为参数创建一个连接到现有队列的队列端点。如果您正在使用没有名称的队列,那么这是您能够为队列创建另一个端点的唯一方法。本机函数OpenMsgQueue用于执行此操作。像CreateMsgQueue这种方法需要一个MsgQueueOptions. 由OpenMsgQueue使用的选项结构中唯一的参数是dwSize和bReadAccess。基本消息队列类的另一个构造函数如下:
C#
这个消息队列实现是一次性的;当它不再被使用时,可以通过调用 dispose 消息来清理它的资源。
子类化队列
当我为消息队列功能编写包装器时,我考虑过在开发人员尝试从只写队列读取或写入只读队列时抛出异常。根本不允许开发人员执行此类无效操作更有意义。所以我把这个MessageQueue 类分成两个类;MessageQueueReader和MessageQueueWriter。每个都包含一组用于读取或写入消息队列的方法,但不能同时包含两者。这些类的构造函数只调用readOnly 参数设置为trueor的基本构造函数false。
写入队列
用于写入队列的方法使用WriteMsgQueue. 如果队列中没有空间可用于写入消息,该方法将阻止调用者。CreateMsgQueue接受一个名为dwTimeout的参数,用于指定调用者在写入请求被视为失败之前将等待多长时间。如果此值设置为INFINITE(数值 -1),则调用将无限期阻塞,直到有足够的可用空间来执行写入。
在我对这个包装器的实现中,开发人员只能以字节数组的形式传递要写入队列的信息。我考虑过使用泛型来使代码更灵活,但我发现了一些误用和滥用这种实现的方法。将她/他的数据转换为字节数组是开发人员的负担。在我的实现中公开了两种写方法。第一个接受消息字节数组和超时值。第二个仅包含消息字节并假定超时值为INFINITE。
从队列中读取
Read方法反映到Write方法;开发人员为该方法提供一个字节缓冲区和一个可选的超时值。如果没有可读取的内容,则调用将阻塞,并且超时值控制方法在读取尝试被视为失败之前等待消息的时间。
读取和写入结果
由于尝试从队列读取或写入队列的失败是正常执行流程的一部分,因此我决定在写入请求失败时不抛出异常。抛出异常会影响性能,所以我尽量不要不必要地抛出它们。相反,这些方法返回枚举类型的值QueueResult。QueueResult.OK表示读取或写入请求的成功完成,其他值表示失败的原因(例如写入请求超时)。
代码示例
读取器/写入器客户端
读取器/写入器客户端示例创建一个消息队列,并允许用户从主 (UI) 线程将消息添加到队列,并在单独的线程上处理来自队列的消息。从用户体验的角度来看,没有太多可看的。有趣的工作都在代码中。
C#
写入客户端
Writer 客户端使用前面的代码示例。它连接到与前面的代码示例相同的队列,并且用户放置在队列中的任何消息都将显示在其他程序中(如果它正在运行)。如果您在不启动阅读器客户端的情况下自行运行编写器客户端,则消息将在队列中累积直到填满。如果您尝试在队列已满时将消息写入队列,请求将阻塞 4 秒,然后返回超时结果。
电源通知队列
电源通知队列示例与我在Windows Mobile Power Management上发表的一篇文章有?关。该程序创建一个队列阅读器,并在调用本机函数时将句柄传递给阅读器队列RequestPowerNotifications。操作系统然后将消息写入队列以通知程序电源状态的变化。通知附加到列表视图的开头。在列表中选择一个项目将导致相关的电源标志显示在屏幕底部。
请求电源通知产生的消息作为结构传递,但我提供的包装器适用于字节数组。我创建了一个新的队列类型,它继承自MessageQueueReader并提供了Read返回电源队列消息的实现。重载Read方法重建PowerBroadcast结构。
C#
public PowerBroadcast Read()
{
PowerBroadcast retVal = new PowerBroadcast();
int bytesRead;
QueueResult result;
result = Read(readBuffer, out bytesRead);
if (QueueResult.OK == result)
{
int message = readBuffer[0] | readBuffer[1] << 8 |
readBuffer[2] << 0x10 | readBuffer[3] << 0x18;
int flags = readBuffer[4] | readBuffer[5] << 8 |
readBuffer[6] << 0x10 | readBuffer[7] << 0x18;
int length = readBuffer[8] | readBuffer[9] << 8 |
readBuffer[10] << 0x10 | readBuffer[11] << 0x18;
retVal.Message = (PowerBroadCastMessageType)message;
retVal.Flags = (PowerBroadcastFlags)flags;
retVal.Length = length;
if ((length > 0)&&( (retVal.Message&PowerBroadCastMessageType.PBT_TRANSITION)
==PowerBroadCastMessageType.PBT_TRANSITION))
{
retVal.SystemPowerState = TextEncoder.GetString(readBuffer,12,length);
}
}
return retVal;
}
结束
我已经介绍了 Windows 消息队列的基本知识,所提供的信息对于更多需要使用消息队列的场景来说应该绰绰有余。但不要停留在这篇文章中。继续阅读有关消息队列和 MSDN 库中的其他命名对象的信息。
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!