ahmd0
ahmd0

Reputation: 17313

Reliable way to count running instances of a process on Windows using c++/WinAPIs

I need to know how many instances of my process are running on a local Windows system. I need to be able to do it using C++/MFC/WinAPIs. So what is a reliable method to do this?

I was thinking to use process IDs for that, stored as a list in a shared memory array that can be accessed by the process. But the question is, when a process is closed or crashes how soon will its process ID be reused?

Upvotes: 3

Views: 3975

Answers (4)

kennbrodhagen
kennbrodhagen

Reputation: 4348

If you are trying to limit the number of instances of your process to some number you can use a Semaphore.
You can read in detail here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686946(v=vs.85).aspx

In a nutshell, the semaphore is initialized with a current count and max count. Each instance of your process will decrement the count when it acquires the semaphore. When the nth process tries to acquire it but the count has reached zero that process will fail to acquire it and can terminate or take appropriate action.

The following code should give you the gist of what you have to do:

#include <windows.h>
#include <stdio.h>

// maximum number of instances of your process
#define MAX_INSTANCES 10

// name shared by all your processes.  See http://msdn.microsoft.com/en-us/library/windows/desktop/aa382954(v=vs.85).aspx
#define SEMAPHORE_NAME "Global\MyProcess"

// access rights for semaphore, see http://msdn.microsoft.com/en-us/library/windows/desktop/ms686670(v=vs.85).aspx
#define MY_SEMAPHORE_ACCESS SEMAPHORE_ALL_ACCESS

DWORD WINAPI ThreadProc( LPVOID );

int main( void )
{
        HANDLE semaphore;

    // Create a semaphore with initial and max counts of MAX_SEM_COUNT

    semaphore = CreateSemaphore( 
        NULL,           // default security attributes
        MAX_INSTANCES,  // initial count
        MAX_INSTANCES,  // maximum count
        SEMAPHORE_NAME ); 

    if (semaphore == NULL) 
    {
        semaphore = OpenSemaphore(
            MY_SEMAPHORE_ACCESS, 
        FALSE, // don't inherit the handle for child processes
        SEMAPHORE_NAME );

        if (semaphore == NULL)
        {
            printf("Error creating/opening semaphore: %d\n", GetLastError());
                return 1;           
        }
    }

    // acquire semaphore and decrement count
    DWORD acquireResult = 0;
        acquireResult = WaitForSingleObject( 
        semaphore,
        0L);  // timeout after 0 seconds trying to acquire

    if(acquireResult == WAIT_TIMEOUT)
    {
        printf("Too many processes have the semaphore.  Exiting.");
        CloseHandle(semaphore);
        return 1;
    }

    // do your application's business here

    // now that you're done release the semaphore
    LONG prevCount = 0;
    BOOL releaseResult = ReleaseSemaphore(
            semaphore,
            1, // increment count by 1
            &prevCount );

    if(!releaseResult)
    {
        printf("Error releasing semaphore");
        CloseHandle(semaphore);
        return 1;
    }

    printf("Semaphore released, prev count is %d", prevCount);

    CloseHandle(semaphore);
    return 0;
}

Upvotes: 2

Logical Fallacy
Logical Fallacy

Reputation: 3107

You can snag the process handles by the name of the process using the method described in this question. It's called Process Walking. That'll be more reliable than process id's or file paths.

A variation of this answer is what you're looking for. Just loop through the processes with Process32Next, and look for processes with the same name using MatchProcessName. Unlike the example in the link I provided, you'll be looking to count or create a list of the processes with the same name, but that's a trivial addition.

Upvotes: 1

Roman Ryltsov
Roman Ryltsov

Reputation: 69724

The process and thread identifiers may be reused any time after closure of all handles. See When does a process ID become available for reuse? for more information on this.

However if you are going to store a pair of { identifier, process start time } you can resolve these ambiguities and detect identifier reuse. You can create a named file mapping to share information between the processes, and use IPC to synchronize access to this shared data.

Upvotes: 1

Marcel N.
Marcel N.

Reputation: 13986

Well, your solution is not very reliable. PIDs can be reused by the OS at any later time. I did it once by going through all the processes and comparing their command line string (the path of the executable) with the one for my process. Works pretty well.

Extra care should be taken for programs that are started via batch files (like some java apps/servers).

Other solutions involve IPC, maybe through named pipes, sockets, shared memory (as you mentioned). But none of them are that easy to implement and maintain.

Upvotes: 0

Related Questions