Process Synchronization events of shared objects on Linux
Source: Internet
Author: User
Process Synchronization events of shared objects on Linux-Linux general technology-Linux programming and kernel information. The following is a detailed description. 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 call is completed. 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 modes, 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.
The second design mode is used 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;
};
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 registration
Static ObjectWithEvents * ms_pObjectWithEvents;
ObjectWithEvents ();
// The implementation for IObjectWithEvents
Void FireEvent ();
Virtual bool AddEventHandler (IEventSink * pEI );
Virtual void SendMessage ();
// Collection for maintaining events
Enum {MAX_EVENT_HANDLERS = 16 ,};
Long m_npEI;
IEventSink * m_apEI [MAX_EVENT_HANDLERS];
Pid_t m_alPID [MAX_EVENT_HANDLERS];
};
IObjectWithEvents * IObjectWithEvents: getInstance ()
{
// The following commented code is for authentication only.
/*
If (NULL = ObjectWithEvents: ms_pObjectWithEvents)
{
ObjectWithEvents: ms_pObjectWithEvents = new ObjectWithEvents ();
}
*/
Void ObjectWithEvents: FireEvent ()
{
// Iterate through the collection
For (long I = 0; I <m_npEI; I ++)
{
// Recheck for NULL
If (0! = M_apEI
) { // Fire the event M_apEI-> OnEvent (m_alPID,""); } }
Void ObjectWithEvents: FireEvent () { // We need to serialize all access to the collection by more than one process Int iRetVal = Initializer: LockMutex ();
If (0! = IRetVal) { Return; }
Pid_t pid = getpid ();
// Iterate through the collection and fire only events belonging to the current process For (long I = 0; I <m_npEI; I ++) { // Check whether the handler belongs to the current process. If (pid! = M_alPID) { Continue; }
// Recheck for NULL If (0! = M_apEI) { M_apEI-> OnEvent (pid ,""); } }
// Release the mutex If (0 = iRetVal) & (0! = Initializer: UnlockMutex ())) { // Deal with error. }
Return; }
// The following are changes to ObjectWithEvents: AddEventHandler ():
// 1. Before accessing the collection, we lock the mutex:
Int bRetVal = Initializer: LockMutex ();
If (0! = BRetVal) { Return false; }
// 2. After accessing the collection, we release the mutex:
If (0 = bRetVal) & (0! = Initializer: UnlockMutex ())) { // Deal with error. }
To instantiate objects in the shared memory, define another class Initializer.
If the shared memory does not exist, create the shared memory and create an object in it. If the shared memory already exists, skip object construction. Initializer: m_shmid records this identifier. ObjectWithEvents: ms_pObjectWithEvents records references to this shared object.
This shared memory will not be destroyed even after all processes are detached from it. In this way, you can use ipcrm to explicitly delete or use the ipcs command for viewing. The compilation method of the test program is as follows:
G ++-g-o shm_client shm_client1.cpp ObjectWithEvents. cpp Initializer. cpp
The result of running this program on the console is as follows:
Listing 8. Console results
$./Shm_client Shm_client1.cpp: 16 Message from pid (4332 ):
$./Shm_client Shm_client1.cpp: 16 Message from pid (4333 ):
$ Ipcrm-m 327686
The ObjectWithEvents instance collects events from various processes. It can only release events registered by the current process. This design pattern describes two points:
Any access to a group of events is protected by a mutex. Filter by process ID before an event is sent.
Shared Memory and event cache for IPC
Now let's take a look at how to use the shared memory and event cache for inter-process communication. If events are cached in shared objects, they may be issued later. The receiving process must query the events of the shared object. Therefore, communication between processes can be achieved by using a Synchronization Model. This is the motivation for developing the following design patterns.
EnqueueEvent () adds an event (such as the message and process id of each event) to a queue. PollForEvents () traverses this queue and calls OnEvent () for events in the queue one by one ().
If (0 = bRetVal) & (0! = Initializer: UnlockMutex ())) { // Deal with error. }
Return true; }
Now try to run the compilation script:
G ++-g-o shm_client1 shm_client1.cpp ObjectWithEvents. cpp Initializer. cpp g ++-g-o shm_client2 shm_client2.cpp ObjectWithEvents. cpp Initializer. cpp
The output on the console should be as follows:
Listing 12. Output of shm_client1 and shm_client2
$./Shm_client1
$./Ipcs
------ Shared Memory Segments -------- Key shmid owner perms bytes nattch status 0x00001234 360454 running in 666 4300 0
$./Shm_client2 Shm_client2.cpp: 16 Message from pid (4454): Message from shm_client1 Shm_client2.cpp: 16 Message from pid (4456): Message from shm_client2
The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion;
products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the
content of the page makes you feel confusing, please write us an email, we will handle the problem
within 5 days after receiving your email.
If you find any instances of plagiarism from the community, please send an email to:
info-contact@alibabacloud.com
and provide relevant evidence. A staff member will contact you within 5 working days.
A Free Trial That Lets You Build Big!
Start building with 50+ products and up to 12 months usage for Elastic Compute Service