Click here to Skip to main content
15,867,488 members
Articles / Desktop Programming / MFC
Article

Shared Memory with IPC with threads

Rate me:
Please Sign up or sign in to vote.
3.32/5 (18 votes)
4 Oct 2004CPOL2 min read 125.3K   4.2K   45   14
Shared memory as used along with threads to communicate between processes.

Introduction

This article concentrates in shared memory design and communication between threads/programs using shared memory. I would break up this article into two sections:

About Shared Memory

When a program loads into the memory, it is broken up into pieces called pages. The communication would exist between the pages of memory or between two independent processes. Anyhow, when a program would like to communicate with another, there should be a common area in the memory for both the programs. This area which is shared between processes is called the Shared Memory. If there was no concept of shared memory, the section of memory occupied by a program could not be accessed by another one thus disabling the concept of sharing data or communication. Then again, in order to reduce integrity of shared data and to avoid concurrent access to the data, kernel provides a mechanism to exclusively access the shared memory resource. This is called mutual exclusion or mutex object.

When a process wants to communicate to another, the following steps take place sequentially:

  1. Take the mutex object, locking the shared area.
  2. Write the data to be communicated into the shared area.
  3. Release the mutex object.

When a process reads from the area, it should repeat the same steps, except that the step 2 should be Read.

About the Code

In order for the program to communicate, the shared memory region should be made when the program starts, at least in this case. This is done by using the following code in the OnCreate function mapped for WM_CREATE message. (You can do this explicitly by adding a handler for WM_CREATE by ClassWizard). Before doing that, write down the global variables (outside any class) as follows:

All these things can be defined in the header file for the implementation file of the shared memory. It can be a dialog box or a document interface.

HANDLE kSendCommand; // Handle for "sending command" event
HANDLE kReceiveCommand; // Handle for "receiving command" event

HANDLE kSendMessage; // Handle for "sending message" event
HANDLE kReceiveMessage; // Handle for "receiving message" event

HANDLE kChildAck; // Handle for "acknowledgement from the child" event

CWinThread* thread; // The thread object

The shared memory structure runs as below:

#define KILL_APP WM_USER+10 // Command to stop the process
#define RECV_MESSAGE WM_USER+20 // Command to receive the message
#define CHILD_START WM_USER+30 // Command when child starts

struct KSharedMemory
{
    DWORD processID; // ID of the process
    BOOL childAck; // Acknowledgment area
    char data[1000]; // The data
    UINT dataSize; // Size of the data

};

UINT StartProbing(LPVOID lParam); // The thread


The OnCreate function would look like this.
     CString title;
//    UpdateData(true);
    if (CDialog::OnCreate(lpCreateStruct) == -1)
        return -1;
    
    
    kProcessId = ::GetCurrentProcessId();
    title.Format("Process: %d",kProcessId);
    this->SetWindowText(title);
    
    /* Create a file map for sharing the memory. This is for sharing
                               the memory between same processes. */
    kMap = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE, 
                           0,sizeof(KSharedMemory),"KBuildDevelop");
    if(GetLastError() == ERROR_ALREADY_EXISTS)
    {
        // COMMENTED SECTION BELOW [TEST]: This was great.
        // Identifies if the process has been created earlier or not. 
        /*MessageBox("One at a time please !!","One At A Time", MB_OK);
        ::PostQuitMessage(0);*/
        kMap = ::OpenFileMapping(FILE_MAP_WRITE,FALSE,"KBuildDevelop");
        kMutex = ::CreateMutex(NULL,FALSE,"KBuildDevelop");
        kParentOrChild = FALSE;
        
    }
    else
    {
        kParentOrChild = TRUE;
    }

    kShMem = (KSharedMemory*)::MapViewOfFile(kMap,FILE_MAP_WRITE, 
                                       0,0,sizeof(KSharedMemory));

The CreateFileMapping function makes the shared memory as a file map. MapViewOfFile function enables sharing of the area created.

kSendCommand = ::CreateEvent(NULL,FALSE,FALSE,"SendCommand");
kSendMessage = ::CreateEvent(NULL,FALSE,FALSE,"SendMessage");
kReceiveMessage = ::CreateEvent(NULL,FALSE,FALSE,"ReceiveMessage");
kReceiveCommand = ::CreateEvent(NULL,FALSE,FALSE,"ReceiveCommand");
kChildAck = ::CreateEvent(NULL,FALSE,FALSE,"ChildAcknowledge");

The CreateEvent function creates events for all the states like sending command, receiving command, sending message, receiving message, and acknowledgement from the child.

To enable message mapping for the user defined commands, include the following lines in the message mapping area:

ON_MESSAGE(KILL_APP,OnKillApp)
ON_MESSAGE(RECV_MESSAGE,OnRecvMessage)
ON_MESSAGE(CHILD_START,OnChildStart)

In the InitDialog function, add the following lines:

if(kParentOrChild) // This is the parent. Receive the message from child.
{
    this->SetWindowText("Parent: Receiving Command");
    GetDlgItem(IDC_BUTTON_KILL)->DestroyWindow();
    GetDlgItem(IDC_EDIT_MESSAGE)->EnableWindow(false);
    GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(false);
    thread = AfxBeginThread(StartProbing,GetSafeHwnd(),
             THREAD_PRIORITY_NORMAL);
             // Start Checking for Commands from Child
    if(thread != NULL)
    {
        UpdateData(true);
        m_status = "Parent waiting for messages ...";
        UpdateData(false);
    }
    else
    {
        UpdateData(true);
        m_status = "Thread not started ...";
        UpdateData(false);
    }
}
else
{
    GetDlgItem(IDC_BUTTON_KILL)->EnableWindow(true);
    kShMem->childAck = TRUE;
    ::SetEvent(kChildAck);
    this->SetWindowText("Child: Send Command / Message to Parent");
}

The other important functions are:

// The thread process
UINT StartProbing(LPVOID lParam)
{
    while(1)
    {
        if(::WaitForSingleObject(kChildAck,10)== WAIT_OBJECT_0)
        /* Wait for acknowledgement from the child */
            PostMessage((HWND) lParam,CHILD_START,0,0);
        if(::WaitForSingleObject(kSendCommand, 10) == WAIT_OBJECT_0)
        {
            PostMessage((HWND) lParam, KILL_APP,0,0);
            ::SetEvent(kReceiveCommand);
            break;
        }    
        else
        {
            // Add code here to wait for another event. 
            if(::WaitForSingleObject(kSendMessage, 10) == WAIT_OBJECT_0)
            {
                PostMessage((HWND) lParam, RECV_MESSAGE,0,0);
                ::SetEvent(kReceiveMessage);
            }
        }
    
    }
    return 0;
}

// When application is killed
void COneAtaTimeDlg::OnKillApp()
{
    PostQuitMessage(0);
}

//When kill button is pressed
void COneAtaTimeDlg::OnButtonKill() 
{
    ::SetEvent(kSendCommand);
    ::ReleaseMutex(kMutex); // Release the mutex object
}
// When send button is pressed
void COneAtaTimeDlg::OnButtonSend() 
{
    UpdateData(true);
    char buffer[100];
    sprintf(buffer,"%s",m_message);
    strcpy(kShMem->data,buffer);
    m_message=_T("");
    UpdateData(false);
    ::SetEvent(kSendMessage);// Set send message event
}

// When message is received
void COneAtaTimeDlg::OnRecvMessage()
{
    UpdateData(true);
    if(strcmp(kShMem->data,"bye")==0)
        PostQuitMessage(0);
    m_recvlist.AddString(kShMem->data);
    UpdateData(false);
}

// When child is started
void COneAtaTimeDlg::OnChildStart()
{
    UpdateData(true);
    m_status = "Child Started...";
    UpdateData(false);

}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
India India
I am a personality from Trivandrum , a green peaceful place in Kerala, South India.
I have been an enthusiast of Windows programming when I started creating simple windows when I learnt VC++ in LCC in Trivandrum. From then on its all about Windows in my flesh and blood.
My career graph moves like this:
1. I started working as a C/C++ programmer in a company in Trivandrum where I learnt the ABCs of Software Industry. I worked with them for about 1 year. I could not contine since I was in contract for 1 year.
2. Then I joined another organization in Trivandrum who gave me challenges to love. They made me mad about VC++ and Windows.
I was mad about Embedded Systems which made me, Myself = Embedded Systems + VC++.
3. Software Engineer in a telecom company in Hyderabad, Andhra Pradesh, S.India.
4. Currently working with a telecom company in Bangalore.
I totally, so, have experience of about 4.5 years.

Comments and Discussions

 
Questionhow to run this code? Pin
Member 130989158-Apr-17 19:19
Member 130989158-Apr-17 19:19 
GeneralProgramming style Pin
Andrew Pye5-Oct-07 0:59
Andrew Pye5-Oct-07 0:59 
GeneralGood Work Pin
Nethaji RAj10-Feb-06 3:09
Nethaji RAj10-Feb-06 3:09 
GeneraleerGood Pin
Nethaji RAj21-Dec-05 5:49
Nethaji RAj21-Dec-05 5:49 
GeneralShared Dynamic Memory with IPC with threads Pin
Bob Hicks5-Jul-05 14:06
Bob Hicks5-Jul-05 14:06 
GeneralRe: Shared Dynamic Memory with IPC with threads Pin
Sreekanth Muralidharan26-Jul-05 17:48
Sreekanth Muralidharan26-Jul-05 17:48 
GeneralWell done! Pin
carmi225-May-05 17:51
carmi225-May-05 17:51 
QuestionThread safe ??? Pin
SuwitLam21-Mar-05 4:57
SuwitLam21-Mar-05 4:57 
AnswerRe: Thread safe ??? Pin
Sreekanth Muralidharan7-Apr-05 18:37
Sreekanth Muralidharan7-Apr-05 18:37 
GeneralThanks Pin
Bijo Issac18-Jan-05 3:35
Bijo Issac18-Jan-05 3:35 
This was very useful for me Thanks
GeneralGreat Intro to Shared Memory Pin
lsanil15-Nov-04 11:08
lsanil15-Nov-04 11:08 
GeneralI have a simple suggestion. Pin
WREY4-Oct-04 20:35
WREY4-Oct-04 20:35 
GeneralGreat job Pin
Andrei Dumitrache4-Oct-04 19:21
Andrei Dumitrache4-Oct-04 19:21 
GeneralRe: Great job Pin
Sreekanth Muralidharan5-Oct-04 22:29
Sreekanth Muralidharan5-Oct-04 22:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.