Click here to Skip to main content
15,886,422 members
Articles / Programming Languages / C++
Article

A Case Study about InterProcess Synchronization

Rate me:
Please Sign up or sign in to vote.
4.25/5 (4 votes)
5 Jan 2001CPOL 121.7K   2K   39   18
An application demonstrating process synchronisation and interprocess communication
  • Download demo project - 142 Kb
  • Download demo executable - 320 Kb
  • Introduction

    When this new website emerged - a wonderful initiative - I decided to endorse it by writing a 'small' sample project which tries to answer a lot of the issues raised concerning interprocess communication. Later on, more and more functionality was added until you see something like IPS is today.

    Image 1

    The Interprocess Communication

    It will show you

    • How to start a child process with a CreateProcess call (based on Joseph M. Newcomer’s code where I removed the resource leak).
    • How to synchronize (= in this case "wait for a process to end") with the Process Handle.
    • How to ‘try’ to end a process cleanly, (If that does not help, shoot the perpetrator down).
    • How to create a Frame Window with a threaded framework solution for watching processes.

    Except for some advanced features concerning process information retrieval that is obtained from calling UNDOCUMENTED APIs and reading from the NT/W2K system table, most things are quite simple with regard to interprocess synchronization.

    The findings or 'techniques' we demonstrate in this article are based on work done by Sven B. Schreiber, and was published comprehensively in the Dr. Dobb's Journal #305 of November 1999 [ (c) 1999 Miller Freeman, Inc., San Francisco (CA) ]. <a href="http: www.ddj.com"="">(www.ddj.com).

    A few C functions to retrieve process information in an OS independent (only MS OS-es were implied here) way are implemented in the "Win32Ext" files. The more interesting ones are:

    • DWORD WINAPI GetProcessModuleName(DWORD dwProcessId, PWORD p_UnicodeString, DWORD dwMaxLength);
    • DWORD WINAPI GetParentProcessId(DWORD dwProcessId, PDWORD p_dwParentPId);
    • DWORD WINAPI GetChildProcesses (DWORD dwProcessId, PDWORD p_dwChildPIds, DWORD dwMaxLength, PDWORD p_dwNrChildren);
    • DWORD WINAPI GetNumberOfProcesses(PDWORD p_dwNrProcesses);
    • DWORD WINAPI GetProcessCommitCharge(DWORD dwProcessId, PDWORD p_dwCommitCharge);
    • DWORD WINAPI GetProcessUserTime(DWORD dwProcessId, PLARGE_INTEGER p_UserTime);
    • DWORD WINAPI GetProcessKernelTime(DWORD dwProcessId, PLARGE_INTEGER p_KernelTime);
    • DWORD WINAPI GetProcessThreadIds(DWORD dwProcessId, PDWORD p_dwThreadIds, DWORD dwMaxLength, PDWORD p_dwNrThreads);
    • DWORD WINAPI GetProcessCreationTime DWORD dwProcessId, PSYSTEMTIME p_SystemTime);
    • DWORD WINAPI GetProcessBasePriority(DWORD dwProcessId, PDWORD p_dwBasePriority);

    Interprocess communication through message dispatching (e.g. used to politely request an application to stop) is done by posting messages to the process windows and was based on code published by Martin-Pierre Frenette. (<a href="http: www.codeproject.com="" threads="" sendmsg.asp"="">Sending a message to the Main Frame Window of Another Application, given only the Process Handle).

    You will also notice that some programs do NOT FOLLOW the standard Parent - Child Process rules: If you would start "Explorer.exe" from within "IPS.exe", you will see that the explorer process is NOT a child of IPS.

    The Process Object and Process Debugger Object

    I rewrote the original IPS code to have somewhat more structure (Let’s face it, it was poor C++, and even now… ). So I came up with the ProcessObject class. It provides an easy way to most things you ever wanted to do with a process. Functions are available to launch and terminate a process, to change its base priority, to send it a message (if it has a window), …

    Also, … you can attach to the target process as a debugger by using a ProcessDebugger Object.

    The Process Debugger is notified of the following events through a C++ call-back mechanism:      

    void OnException(DebugEvent_Exception* pDE);
    void OnProcessStart(DebugEvent_Process* pDE);
    void OnProcessExit(DebugEvent_Process* pDE);
    void OnThreadStart(DebugEvent_Thread* pDE);
    void OnThreadExit(DebugEvent_Thread* pDE);
    void OnDllLoad(DebugEvent_DLL* pDE);
    void OnDllUnload(DebugEvent_DLL* pDE);
    void OnDebugOutput(DebugEvent_Output* pDE);

    The respective pointers to the DebugEvent objects provide all the necessary information during the events. Getting the Debug functions to work can be error prone, so if you want a simplified idea of how the VC Debugger does it, check it out.

    The ProcessDebugger also has a nifty Thread Stack Dumper Object (through aggregation), which can come in handy if you want to know the exact context of an exception for example. I found my sample of stack dumping functionality at Felix Kaska’s Win32 Pages ( http://mvps.org/win32/ ). I (almost completely) rewrote the functionality and put it in the respective StackFrame and ThreadFunctionStack classes. It provides functionality to dump the stack of a thread inside its own process, possibly as a reaction to an exception (but not only at that time), and it is also possible to dump the stack of a thread in another process (if you have the necessary DEBUG privileges, of course). The debug symbols, if available, are only loaded when needed. It’s up to the software engineer to decide whether he or she wants to put a minimal amount of debug information into the executable. If a ‘.map’ file was built (in the link step), the information provided by the stack dump in combination with the map file should be sufficient to figure out the function context even when no debug information is included in the executable. (Read MSDN if you are not sure how to add and choose the type of debug information). If more debug symbol information (besides registers and instruction pointers) is available in the executable, it will be used (by IPS through the ImageHlp dll) and logged which makes it a lot easier to figure out what went wrong.

    Image 2

    Tracing

    For internal bug tracking IPS uses the TraceLogger class, which can log or trace functions (and function returns), errors and unhandled exceptions to a log file. By using macros we can put extra information in the log file to make our debugging tasks in the field easier. If required, the log file can be split up into separate parts (for file usage rotation purposes, so the maximum file size used by the logger is limited), which could be encrypted using for example a CryptLib or an in-house developed stream encryption algorithm. IPS does not encrypt the log file because the source is there for everyone to see. If an unhandled exception occurs, naturally IPS will stack dump its own offending thread before terminating. (If you would be so kind as to send the log file to me if that happens.)

    The Trace Level can be adjusted at run-time (see the IPS about box).

    You could also remove some of the function tracing by redefining the macros to empty statements (and recompiling the Application) :

    LOGTRACE(l, s) 
    LOGTRACEFUNC(s)
    LOGTRACEERROR(e, s)
    LOGTRACEFUNCRETURN(e, s)
    LOGTRACEDUMPSTACK()
    LOGTRACEOSTREAM(s)
    LOGTRACEPROGRESSWITHOSTREAM() 

    Live Debug Output Window

    For Logging the debug event, I used a slightly modified version of TOutputWnd made by Ben Ashley. The original version can be found at CodeGuru ( www.codeguru.com ). The IPS user can dump the log file in text format, which can be used to point the support department or developer of the crashed program to the offending code. (Doh!)

    Future Enchancements

    System wide Hooking of the CreateProcess (and CreateThread) calls to improve performance instead of using a dumb timer.

    Just wondering whether it is necessary to dump all the threads on a program crash…

    Provide real UNICODE compliant code.

    Other (Any suggestions?)

    Note on the Compiler Used

    I used an evaluation version of the Intel 5.0 Compiler, which produces (much bigger) faster and automatically optimised code for the Intel PI/PII/PIII family. It integrates seamlessly in the MS VC Development environment and is fully (?) compatible with the MS VC Compiler.

    Gert Boddaert, Alias GBO.

    License

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


    Written By
    Technical Lead rtos.be
    Belgium Belgium
    Gert Boddaert is an experienced embedded software architect and driver developer who worked for companies such as Agfa Gevaert, KBC, Xircom, Intel, Niko, (Thomson) Technicolor, Punch Powertrain, Fifthplay, Cisco and Barco. For more obscure details, please take a look at his LinkedIn profile. Anyway, he started out as a Commercial Engineer – option “Management Informatics”, but was converted to the code-for-food religion by sheer luck. After writing higher level software for a few years, he descended to the lower levels of software, and eventually landed on the bottom of embedded hell… and apparently still likes it down there.

    His favourite motto: “Think hard, experiment and prototype, think again, write (easy and maintainable) code”,

    favourite quote: “If you think it’s expensive to hire a professional to do the job, wait until you hire an amateur.” – by Red Adair,

    I can be contacted for real-time embedded software development projects via http://www.rtos.be and http://www.rtos.eu

    Comments and Discussions

     
    QuestionWMI, Win32ext_WPD, Windows Portables Devices, and C# Pin
    kiquenet.com25-Aug-14 22:55
    professionalkiquenet.com25-Aug-14 22:55 
    Questionshared memory with mm.h in C??? Pin
    mora2629-Oct-05 14:44
    mora2629-Oct-05 14:44 
    QuestionCan we write a self destructing exe?? Pin
    26-Feb-01 20:04
    suss26-Feb-01 20:04 
    AnswerRe: Can we write a self destructing exe?? Pin
    Gert Boddaert26-Feb-01 21:37
    Gert Boddaert26-Feb-01 21:37 
    GeneralError in OS win2000 Pin
    16-Jan-01 16:57
    suss16-Jan-01 16:57 
    GeneralRe: Error in OS win2000 Pin
    Gert Boddaert16-Jan-01 21:33
    Gert Boddaert16-Jan-01 21:33 
    GeneralIMPORTANT BUILD INFORMATION Pin
    Gert Boddaert17-Jan-01 2:26
    Gert Boddaert17-Jan-01 2:26 
    GeneralModelling MT synchronization Pin
    Michael Welsch9-May-00 1:34
    Michael Welsch9-May-00 1:34 
    GeneralRe: Modelling MT synchronization Pin
    ana_v12316-Nov-05 20:16
    ana_v12316-Nov-05 20:16 
    GeneralAccess denied Pin
    James Khan6-May-00 13:41
    James Khan6-May-00 13:41 
    GeneralRe: Access denied Pin
    Gert Boddaert8-May-00 0:07
    Gert Boddaert8-May-00 0:07 
    GeneralNOVO Pin
    webmaher2-May-00 20:54
    susswebmaher2-May-00 20:54 
    GeneralKilling a process with an "Application Error" Pin
    oystein16-Feb-00 21:37
    oystein16-Feb-00 21:37 
    GeneralRe: Killing a process with an Pin
    shahram moghtanam1-Jul-00 19:44
    sussshahram moghtanam1-Jul-00 19:44 
    GeneralRe: Killing a process that crashes but you have a debugger installed... Pin
    Gert Boddaert3-Jul-00 21:48
    Gert Boddaert3-Jul-00 21:48 
    GeneralIt also works on Windows 2000 Pin
    Gert Boddaert20-Jan-00 8:34
    Gert Boddaert20-Jan-00 8:34 
    GeneralRe: It also works on Windows 2000 Pin
    aanandg8-Jun-00 9:10
    aanandg8-Jun-00 9:10 
    GeneralRe: It also works on Windows 2000 Pin
    Gert Boddaert8-Jun-00 21:09
    Gert Boddaert8-Jun-00 21:09 

    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.