在面向?qū)ο蟮南到y(tǒng)中,當(dāng)一個(gè)對(duì)象接收到一條消息時(shí),可能會(huì)發(fā)生一系列的事件。通常,這些事件是以 同步(synchronous) 模式處理的:調(diào)用進(jìn)程或向這個(gè)對(duì)象發(fā)送消息的線(xiàn)程在發(fā)送消息調(diào)用完成之前都會(huì)接收并處理一系列事件。然而,如果產(chǎn)生這些事件的對(duì)象是由多個(gè)進(jìn)程進(jìn)行共享并且保存在共享內(nèi)存中時(shí),情況就稍微有些不同了。
本文將使用兩種 C++ 設(shè)計(jì)模式來(lái)詳細(xì)介紹這種情況,并使用一些樣例代碼來(lái)展示這種解決方案(這些樣例代碼可以從本文 下載 一節(jié)中獲得):
我們將簡(jiǎn)要介紹不使用共享內(nèi)存的樣例代碼。
使用第一種設(shè)計(jì)模式來(lái)修改這些代碼,讓其使用共享內(nèi)存。
然后闡述如何使用第二種設(shè)計(jì)模式來(lái)實(shí)現(xiàn)進(jìn)程間通信(IPC)。 您可以在任何機(jī)器體系架構(gòu)、操作系統(tǒng)和編譯器上應(yīng)用這兩種設(shè)計(jì)模式中的概念。對(duì)于本文來(lái)說(shuō),我們使用的是 RedHat Linux 7.1 for 32-bit x86 Intel? 體系架構(gòu)的發(fā)行版;使用 GNU C++ compiler version 3.2.3 編譯器及其相關(guān)工具來(lái)編譯并測(cè)試樣例程序。
不使用共享內(nèi)存
下面讓我們開(kāi)始介紹這個(gè)樣例程序,首先是不使用共享內(nèi)存的程序:
清單 1. common.h<
#ifndef __COMMON_H__
#define __COMMON_H__
class IObjectWithEvents
{
public:class IEventSink{public:virtual void OnEvent(pid_t pid, const char * msg) = 0;};
static IObjectWithEvents * getInstance();
virtual bool AddEventHandler(IEventSink * pEI) = 0;virtual void SendMessage() = 0;
};
#endif //__COMMON_H__
|
接口類(lèi) IObjectWithEvents 包含了一個(gè)內(nèi)嵌的接口類(lèi) IEventSink,它定義了 OnEvent() 方法。這個(gè)事件處理程序接收一個(gè)發(fā)送者的 id 和一個(gè)字符串消息。getInstance() 方法返回對(duì)共享內(nèi)存中對(duì)象的引用,AddEventHandler() 注冊(cè)一個(gè)事件處理程序,SendMessage() 向這個(gè)對(duì)象發(fā)送一條消息。由于不需要引用共享內(nèi)存,所以可以像清單 2 中那樣來(lái)使用 IObjectWithEvents:
清單 2. shm-client1.cpp<
#include
#include
#include
#include "common.h"
#define HERE __FILE__ << ":" << __LINE__ << " "
using namespace std;
class EventSink : public IObjectWithEvents::IEventSink
{
public:void OnEvent(pid_t pid, const char * msg){cout << HERE << "Message from pid(" << pid << ")\t : " << msg << endl;}
};
int main()
{IObjectWithEvents * powe = IObjectWithEvents::getInstance();
EventSink sink;powe->AddEventHandler(&sink);
powe->SendMessage();return 0;
}
|
類(lèi) EventSink 提供了這個(gè)事件處理程序的實(shí)現(xiàn)。主函數(shù)中給出了用于發(fā)送消息和處理事件的標(biāo)準(zhǔn)序列。
ObjectWithEvents 的典型實(shí)現(xiàn)如清單 3、4 所示:
清單 3. ObjectWithEvents.h
#include "common.h"
class ObjectWithEvents : public IObjectWithEvents
{
public:// We assume singleton design pattern for illustrationstatic ObjectWithEvents * ms_pObjectWithEvents;
ObjectWithEvents();
//the implementation for IObjectWithEventsvoid FireEvent();virtual bool AddEventHandler(IEventSink * pEI);virtual void SendMessage();
//Collection for maintaining eventsenum { MAX_EVENT_HANDLERS = 16, };long m_npEI;IEventSink * m_apEI[MAX_EVENT_HANDLERS];pid_t m_alPID[MAX_EVENT_HANDLERS];
};
|
清單 4. ObjectWithEvents.cpp
#include
#include
#include
#include
#include
#include "ObjectWithEvents.h"
using namespace std;
ObjectWithEvents * ObjectWithEvents::ms_pObjectWithEvents = NULL;
IObjectWithEvents * IObjectWithEvents::getInstance()
{// the following commented code is for illustration only./*if (NULL == ObjectWithEvents::ms_pObjectWithEvents){ObjectWithEvents::ms_pObjectWithEvents = new ObjectWithEvents();}*/
return ObjectWithEvents::ms_pObjectWithEvents;
}
ObjectWithEvents::ObjectWithEvents() : m_npEI(0)
{
}
void ObjectWithEvents::FireEvent()
{// iterate through the collectionfor (long i = 0; i < m_npEI; i++){//Recheck for NULLif (0 != m_apEI[i]){// Fire the eventm_apEI[i]->OnEvent(m_alPID[i], "");}}
return;
}
bool ObjectWithEvents::AddEventHandler(IEventSink * pEI)
{// NULL checkif (NULL == pEI){return false;}
// check if there is space for this event handlerif (MAX_EVENT_HANDLERS == m_npEI){return false;}
// Add this event handler to the collectionm_alPID[m_npEI] = getpid();m_apEI[m_npEI++] = pEI;
return true;
}
void ObjectWithEvents::SendMessage()
{//Some processing//And then fire the event
FireEvent();
return;
}
|
清單 4 中的代碼可以使用下面的腳本來(lái)編譯:
g++ -g -o shm_client shm_client1.cpp ObjectWithEvents.cpp
|
在運(yùn)行 shm_client 時(shí),應(yīng)該可以看到下面的輸出:
$ ./shm_client shm_client1.cpp:16 Message from pid(3920) :
|
使用共享內(nèi)存:沒(méi)有事件緩存
現(xiàn)在,為了在共享內(nèi)存中對(duì) ObjectWithEvents 進(jìn)行實(shí)例化,我們需要修改 ObjectWithEvents 的實(shí)現(xiàn)。