用于与服务提供商交互的跨平台 IPC 事件管理器
本文介绍如何使用共享内存队列通过Windows和Linux平台在进程之间发送或发布事件。
引言
事件驱动编程或基于事件的编程是一种编程范式,其中程序的流程由事件决定,即传感器输出或用户操作(鼠标点击、按键)或来自其他程序或线程的消息。
由于事件交互的复杂性,事件驱动应用程序通常以状态机模式组织。IPC事件队列管理器是支持基于事件的编程所必需的。
与服务提供商交互
事件驱动应用程序可能与低层软件模块或硬件接口(称为服务提供商)进行操作。服务由一组可供服务用户(应用程序)使用的原语(操作)正式指定。这些原语告诉服务执行某些操作或报告对等组件/实体已执行的操作。服务原语分为四类
- 请求
- 指示
- 响应
- Confirm
[计算机网络,Andrew S.Tanenbaum]。请求和确认原语可以实现为服务调用的形式。指示和响应原语可以实现为外部事件发布的。(此处的英文原文为 "[Computer Networks, Andrew S.Tanenbaum]. The request and confirm primitives can be implemented in the form of service calls. The indication and response primitives can be implemented in the form of external event posting.")
活动状态机对象可以使用以下机制之一与服务提供商通信以交换信息
- 同步服务调用。这些同步服务调用可能会阻塞,直到操作完成才将控制权返回给应用程序。由于大多数实时系统必须在预定的时间内响应外部事件,因此不使用同步服务调用。
- 异步服务调用。异步函数不会阻塞,而是继续执行,并在操作完成之前返回。
- 主动事件指示。这些事件是从服务组件发布到客户端组件,而无需任何请求。一个例子可能是由硬件中断服务例程发布的事件。

平台无关的应用开发
嵌入式系统市场中有许多不同的操作系统或硬件。每个不同的操作系统都提供不同的API来访问一组通用的系统服务。OS虚拟层提供了一个平台无关的适配器层,允许状态机在不同操作系统之间移植。
IPC事件管理器
IPC共享内存可用于在不同进程之间共享信息。然而,在实际工程中,源进程可能请求将一个事件发送到目标进程,并且在事件被目标进程接收之前不会返回。或者,将一个事件发布到目标进程,该进程只是将事件留在队列中,然后立即返回。目标进程然后查询可用事件并根据事件类型采取特定操作。
IPC事件队列管理器需要支持同步事件处理和异步事件处理。
Using the Code
类 XSharedMemoryQueue
此模块管理一组共享内存队列。每个队列都是一个双向链表。该类包含一组指向这些队列的队列头。当创建该类的一个实例时,所有队列节点都会链接到第一个队列。其他队列为空。
class XSharedMemoryQueue
{
public:
XSharedMemoryQueue();
~XSharedMemoryQueue();
bool Initialize (const char* strMapName, int iNodeSize,
int iNodeCount, int iQueueCount);
void Release ();
void* CreateSharedMemoryQueue ();
void DeleteSharedMemoryQueue ();
void* OpenSharedMemoryQueue ();
void CloseSharedMemoryQueue ();
void* GetAt(int iIndex);
int GetIndex(void* pNode);
void* GetQueueHead(int iQueue);
void* GetQueueTail(int iQueue);
void* GetNext(void* pNode);
void* GetPrev(void* pNode);
bool MoveToDestQueueTail(void* pNode, int iDestQueue);
int LocateQueue(void* pNode);
void DumpQueue (int iQueue, bool bDumpNode);
void DumpNode (void* pNode);
private:
char* m_strMapName;
int m_iNodeSize; // the size of internal node which contains
// additional pointers besides user data.
int m_iNodeCount; // the node count
int m_iQueueCount; // the number of queues
int* m_pQueueArray; // the queue array
shared_memory_t m_hMapMem;
void* m_pMappedPointer;
};
-
bool XSharedMemoryQueue:: Initialize (const char* strMapName, int iNodeSize, int iNodeCount, int iQueueCount);
-
void*XSharedMemoryQueue::CreateSharedMemoryQueue ();
-
void XSharedMemoryQueue::OpenSharedMemoryQueue ();
-
void XSharedMemoryQueue::DeleteSharedMemoryQueue ();
-
void XSharedMemoryQueue::CloseSharedMemoryQueue ();
-
void * XSharedMemoryQueue::GetQueueHead(int iQueue);
-
void * XSharedMemoryQueue::GetQueueTail(int iQueue);
-
void * XSharedMemoryQueue::GetNext(void* pNode);
-
void * XSharedMemoryQueue::GetPrev(void* pNode);
-
bool MoveToDestQueueTail(void* pNode, int iDestQueue);
初始化一组共享内存队列。Initialize()
定义对象名称、共享内存队列数量、队列节点大小和队列数。
创建一组共享内存队列。Windows版本中的函数创建一个命名的文件映射对象。Linux版本中的函数创建一个共享内存对象。对于进程间通信,主进程调用此函数来创建一组共享内存队列。
打开一组共享内存队列。Windows版本中的函数打开现有的命名文件映射对象。Linux版本中的函数打开现有的共享内存对象。对于进程间通信,从属进程调用此函数来创建一组共享内存队列。
删除一组共享内存队列。Windows版本中的函数删除命名的文件映射对象。Linux版本中的函数删除共享内存对象。对于进程间通信,主进程调用此函数来删除一组共享内存队列。
关闭一组共享内存队列。Windows版本中的函数关闭现有的命名文件映射对象。Linux版本中的函数关闭现有的共享内存对象。对于进程间通信,从属进程调用此函数来关闭一组共享内存队列。
返回给定队列的头部。
返回给定队列的尾部。
返回队列节点的下一个项。
返回队列节点的前一个项。
将给定节点从源队列移除并添加到目标队列。如果目标队列为空,则将该节点添加为队列的头部。如果目标队列非空,则将该节点追加到目标队列。
结构 IPCEventInfo
定义进程间通信事件信息的结构。
类 XExtIPCEvent
操作一组共享内存队列,以将事件发送或发布到目标进程。
枚举定义了三个共享内存队列。
{IPC_QUEUE_RESOURCE=0,IPC_QUEUE_SENDING=1,IPC_QUEUE_POSTING=2};
IPC_QUEUE_RESOURCE
是一个IPC事件块池。IPC_QUEUE_SENDING
是一个IPC事件队列,其中事件正在发送过程中。IPC_QUEUE_POSTING
是一个IPC事件队列,其中事件将要被发布。
struct IPCEventInfo
{
int SourceProcessID;
int DestProcessID;
int IPCEventStatus;
int EventID;
unsigned long ulParameter1;
unsigned long ulParameter2;
};
typedef int (*SME_IPC_EVENT_CALLBACK_T)(void* pInEventInfo);
class XExtIPCEvent
{
public:
XExtIPCEvent();
~XExtIPCEvent();
enum {IPC_EVENT_BUFFER_SIZE=1024};
enum {IPC_QUEUE_NUMBER=4};
enum {IPC_QUEUE_RESOURCE=0,IPC_QUEUE_SENDING=1,IPC_QUEUE_POSTING=2};
//Four queues: empty, send queue, wait for sending, and post
enum TmCommandStatus
{
EVENT_STATUS_UNUSED = 0, EVENT_STATUS_SENDING,
EVENT_STATUS_POSTING,
EVENT_STATUS_CONSUMED
};
static XExtIPCEvent* GetInstance ();
int Initialize (int ProcessID, bool bIsMasterProcess = false);
void Release (bool bIsMasterProcess = false);
int SendIPCEvent(IPCEventInfo* pInEventInfo,
IPCEventInfo* pOutEventInfo,
int nTimeout = -1);
int PostIPCEvent(IPCEventInfo* pInEventInfo);
int QueryIPCEvent(IPCEventInfo* pOutEventInfo,
SME_IPC_EVENT_CALLBACK_T pfnCallbak);
void RecycleEvent(int idProcess);
bool DumpInfo ();
private:
int Lock ();
int UnLock();
private:
XSharedMemoryQueue* m_pSMQueue;
XSemaphore* m_pSem;
int m_idProcess;
};
-
int XExtIPCEvent::Create (int ProcessID, bool bIsMasterProcess = false);
-
int XExtIPCEvent::SendIPCEvent(IPCEventInfo* pInEventInfo, IPCEventInfo* pOutEventInfo, int nTimeout = -1);
-
int XExtIPCEvent::PostIPCEvent(IPCEventInfo* pInEventInfo);
-
int XExtIPCEvent::QueryIPCEvent(IPCEventInfo* pOutEventInfo, SME_IPC_EVENT_CALLBACK_T pfnCallbak);
-
void XExtIPCEvent::RecycleEvent(int idProcess);
使用进程ID和主进程信息创建XSharedMemoryQueue
的实例。
将IPC事件发送到目标进程。函数将在事件被目标进程接收后才会返回。
将IPC事件发布到发布队列并立即返回。
IPC事件接收进程调用此函数来查询IPC事件。
将由给定进程发送的事件回收回事件池,或者当目标进程是给定进程时回收。
关注点
这是开源项目StateWizard的一个组件,StateWizard是一个类似于ClassWizard的往返UML动态建模/开发工具。您可以在 http://www.intelliwizard.com/ 下载其他组件。