Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Interprocess Communication using Shared Memory

0.00/5 (No votes)
13 Dec 1999 3  
A client-server model using shared memory for interprocess communication
  • Download demo project - 10 Kb
  • This article presents a client/server model where the communication between processes is done using shared memory. Since shared memory may be used only on a single machine, all processes must run on a same computer. This is an obvious limitation. However, the advantage is a speed of communication (note that speed may be severely compromised by a bad implementation on both sides - client and server). Another advantage is that this method is available on any platform (Windows 95/98 as well as Windows NT).

    Using shared memory enables us to design a system where we have a single server and multiple clients communicating in both directions with the server. Communication is initiated by the client -- server is normally in idle state waiting for the client request. Communication is thread safe is a sense that only a single client may exchange information with the server at any moment of time.

    Both client and server must create several global named objects:

    • File mapping object that is mapped to a pointer to application specific structure within each process.
    • Two (2) named events for communication between the server and a single client.
    • Mutex to synchronize excess to the server among multiple clients.
    Synchronization among different clients is explained with the following pseudo code:
    // Client wants to communicate with the server
    
    if WaitForSingleObject(global named mutex object) is free then
        execute communication session with the server (see below)
        ReleaseMutex(global named mutex object)
    This ensures that only a single client may execute a communication session with the server. While the communication session is active, every other client is waiting for the global named mutex object (of course, only if it needs to communicate with the server at exactly the same moment as any other client). This protection is not needed on the server side (it does not need the global named mutex object) since client request is guarantied to come from a single client at a time.

    Following pseudo code shows how the communication session is performed between the server and a client:

    Client side

    if WaitForSingleObject(global named mutex object) is free then
       Fill application specific structure mapped as a shared memory
       SetEvent(m_hExec)
       if WaitForSingleObject(m_hDone, timeout) is WAIT_OBJECT_0 then
          Handle values in the application specific structure returned from the server
       else
          Timeout waiting for the server
       ReleaseMutex(global named mutex object)
    

    Server side

    if WaitForSingleObject(m_hExec, timeout) is WAIT_OBJECT_0 then
       Get values from the application specific structure
       Set return values
       SetEvent(m_hDone)
    

    The timeout used in a WaitForSingleObject on the client side depends on the task that is done within the server. In order to speed up the communication, server needs to be as fast as possible.

    Timeout used in a WaitForSingleObject on the server side depends on the server side implementation. Sample code (for simplicity) uses a timer handler that periodically checks for client side requests. In a real production code, one should use a separate thread and a WaitForMultipleObjects function that waits for event m_hExec and at the same time for the event that will shutdown the thread (application exit). In this case, timeout may be infinite. This will improve server performance dramatically since it will be able to respond to client request immediatelly (the delay may be only if it is already handling another client request).

    Usually, server is started first and any client started later will connect to the server. Sample project is designed in a way that the first instance is automatically the server and any other instance started later is a client. The communication handles correctly the situation when the server is closed while the clients are running.  What needs the special consideration is the initialization phase when the server and clients are distinct and different applications. In this case, there is a possibility to prevent starting the client if the server is not running or to allow the client to run but to check (and connect) to the server when the client needs to send something to the server. Following pseudo code shows initialization of the client and the server:

    Client side

    m_hMap = OpenFileMapping(...)
    if m_hMap is NULL then
       Server is not running
    else
       pointer to structure = MapViewOfFile(m_hMap, ...)
    

    Server side

    m_hMap = CreateFileMapping(...)
    if GetLastError() is ERROR_ALREADY_EXISTS then
       Server is either started for the second time or previous server instance 
          is killed while the clients are still running.
    pointer to structure = MapViewOfFile(m_hMap, ...)
    

    Multiple instances of the server must be prevented. This can be done using any of the techniques to prevent multiple instances of a single application.

    This design is used in the Runtime Monitoring Agent and performs very good. Multiple clients (from different proceses and threads) are able to communicate with the single server in a very fast and reliable manner.

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here