In an object-oriented system, when an object receives a message, a series of events may occur. Generally, these events are processed in synchronous mode: The Calling process or the thread that sends a message to this object receives and processes a series of events before the message sending call is complete. However, if the objects that generate these events are shared by multiple processes and saved in the shared memory, the situation is slightly different.
This article will introduce this situation in detail using two C ++ design patterns, and use some sample code to demonstrate this solution. These sample code can be obtained from the download section of this article):
We will briefly introduce the sample code that does not use shared memory.
Use the first design mode to modify the code and use the shared memory.
Then explain how to use the second design mode to implement inter-process communication IPC ). You can apply the concepts in these two design patterns on any machine architecture, operating system, or compiler. For this article, we use RedHat Linux 7.1 for 32-bit x86 Intel? The release version of the architecture. Use the gnu c ++ compiler version 3.2.3 compiler and related tools to compile and test the sample program.
Do not use shared memory
Let's start with the example program. The first is a program that does not use shared memory:
Listing 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__ |
The Interface Class IObjectWithEvents contains an embedded interface class IEventSink, which defines the OnEvent () method. This event handler receives a sender's id and a string message. The getInstance () method returns a reference to an object in the shared memory. AddEventHandler () registers an event handler and SendMessage () sends a message to this object. Because shared memory does not need to be referenced, you can use IObjectWithEvents as in Listing 2:
Listing 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;}
|
EventSink class provides the implementation of this event handler. The main function provides a standard sequence for sending messages and processing events.
Typical implementations of ObjectWithEvents are shown in listing 3 and 4:
Listing 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];}; |
Listing 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 eventFireEvent();return;}
|
The code in Listing 4 can be compiled using the following script:
g++ -g -o shm_client shm_client1.cpp ObjectWithEvents.cpp |
When running shm_client, you can see the following output:
$ ./shm_client shm_client1.cpp:16 Message from pid(3920) : |
Use shared memory: No event Cache
Now, to instantiate ObjectWithEvents in the shared memory, we need to modify the implementation of ObjectWithEvents.