2

我需要知道我的进程有多少实例在本地 Windows 系统上运行。我需要能够使用 C++/MFC/WinAPIs 来做到这一点。那么有什么可靠的方法来做到这一点呢?

我正在考虑为此使用进程 ID,将其作为列表存储在进程可以访问的共享内存数组中。但问题是,当一个进程关闭或崩溃时,它的进程 ID 多久会被重用?

4

4 回答 4

1

您可以使用此问题中描述的方法通过进程名称来获取进程句柄。它被称为过程行走。这将比进程 ID 或文件路径更可靠。

您正在寻找此答案的变体。只需使用 循环遍历进程Process32Next,并使用 查找具有相同名称的进程MatchProcessName。与我提供的链接中的示例不同,您将希望计算或创建具有相同名称的进程列表,但这是一个微不足道的补充。

于 2012-06-16T21:31:13.810 回答
1

进程和线程标识符可以在所有句柄关闭后的任何时间重用。请参阅进程 ID 何时可以重用?有关这方面的更多信息。

但是,如果您要存储一对 { identifier, process start time },您可以解决这些歧义并检测标识符重用。您可以创建命名文件映射以在进程之间共享信息,并使用 IPC 同步访问此共享数据。

于 2012-06-16T21:31:48.317 回答
1

如果您试图将进程的实例数限制为某个数量,则可以使用信号量。
您可以在这里详细阅读:http: //msdn.microsoft.com/en-us/library/windows/desktop/ms686946 (v=vs.85).aspx

简而言之,信号量使用当前计数和最大计数进行初始化。进程的每个实例在获取信号量时都会递减计数。当第 n 个进程尝试获取它但计数已达到零时,该进程将无法获取它并且可以终止或采取适当的措施。

以下代码应该为您提供必须做的事情的要点:

#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;
}
于 2012-06-17T00:08:45.950 回答
0

好吧,您的解决方案不是很可靠。操作系统可以在以后的任何时间重用 PID。我通过遍历所有进程并将它们的命令行字符串(可执行文件的路径)与我的进程的命令行字符串进行比较来完成一次。效果很好。

应特别注意通过批处理文件启动的程序(如某些 java 应用程序/服务器)。

其他解决方案涉及 IPC,可能通过命名管道、套接字、共享内存(如您所述)。但是它们都不是那么容易实现和维护的。

于 2012-06-16T21:26:05.770 回答