我需要知道我的进程有多少实例在本地 Windows 系统上运行。我需要能够使用 C++/MFC/WinAPIs 来做到这一点。那么有什么可靠的方法来做到这一点呢?
我正在考虑为此使用进程 ID,将其作为列表存储在进程可以访问的共享内存数组中。但问题是,当一个进程关闭或崩溃时,它的进程 ID 多久会被重用?
进程和线程标识符可以在所有句柄关闭后的任何时间重用。请参阅进程 ID 何时可以重用?有关这方面的更多信息。
但是,如果您要存储一对 { identifier, process start time },您可以解决这些歧义并检测标识符重用。您可以创建命名文件映射以在进程之间共享信息,并使用 IPC 同步访问此共享数据。
如果您试图将进程的实例数限制为某个数量,则可以使用信号量。
您可以在这里详细阅读: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;
}
好吧,您的解决方案不是很可靠。操作系统可以在以后的任何时间重用 PID。我通过遍历所有进程并将它们的命令行字符串(可执行文件的路径)与我的进程的命令行字符串进行比较来完成一次。效果很好。
应特别注意通过批处理文件启动的程序(如某些 java 应用程序/服务器)。
其他解决方案涉及 IPC,可能通过命名管道、套接字、共享内存(如您所述)。但是它们都不是那么容易实现和维护的。