如何使用Windows API直接将进程"assign"到信号量?

How to directly "assign" a process to a semaphore using windows API?

本文关键字:assign 信号量 进程 Windows 何使用 API      更新时间:2023-10-16

我使用来自Microsoft的以下代码作为模板:

#include <windows.h>
#include <stdio.h>
#define MAX_SEM_COUNT 10
#define THREADCOUNT 12
HANDLE ghSemaphore;
DWORD WINAPI ThreadProc( LPVOID );
int main( void )
{
HANDLE aThread[THREADCOUNT];
DWORD ThreadID;
int i;
// Create a semaphore with initial and max counts of MAX_SEM_COUNT
ghSemaphore = CreateSemaphore( 
NULL,           // default security attributes
MAX_SEM_COUNT,  // initial count
MAX_SEM_COUNT,  // maximum count
NULL);          // unnamed semaphore
if (ghSemaphore == NULL) 
{
printf("CreateSemaphore error: %dn", GetLastError());
return 1;
}
// Create worker threads
for( i=0; i < THREADCOUNT; i++ )
{
aThread[i] = CreateThread( 
NULL,       // default security attributes
0,          // default stack size
(LPTHREAD_START_ROUTINE) ThreadProc, 
NULL,       // no thread function arguments
0,          // default creation flags
&ThreadID); // receive thread identifier
if( aThread[i] == NULL )
{
printf("CreateThread error: %dn", GetLastError());
return 1;
}
}
// Wait for all threads to terminate
WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
// Close thread and semaphore handles
for( i=0; i < THREADCOUNT; i++ )
CloseHandle(aThread[i]);
CloseHandle(ghSemaphore);
return 0;
}
DWORD WINAPI ThreadProc( LPVOID lpParam )
{
// lpParam not used in this example
UNREFERENCED_PARAMETER(lpParam);
DWORD dwWaitResult; 
BOOL bContinue=TRUE;
while(bContinue)
{
// Try to enter the semaphore gate.
dwWaitResult = WaitForSingleObject( 
ghSemaphore,   // handle to semaphore
0L);           // zero-second time-out interval
switch (dwWaitResult) 
{ 
// The semaphore object was signaled.
case WAIT_OBJECT_0: 
// TODO: Perform task
printf("Thread %d: wait succeededn", GetCurrentThreadId());
bContinue=FALSE;            
// Simulate thread spending time on task
Sleep(5);
// Release the semaphore when task is finished
if (!ReleaseSemaphore( 
ghSemaphore,  // handle to semaphore
1,            // increase count by one
NULL) )       // not interested in previous count
{
printf("ReleaseSemaphore error: %dn", GetLastError());
}
break; 
// The semaphore was nonsignaled, so a time-out occurred.
case WAIT_TIMEOUT: 
printf("Thread %d: wait timed outn", GetCurrentThreadId());
break; 
}
}
return TRUE;
}

我想对其进行调整,使其不是由线程来决定信号量如何填充,而是由进程来完成,这意味着如果有进程在运行和/或它们的任何一个habdles没有关闭,信号量就会填充,事实上,我已经通过用这个新函数改变线程函数的工作方式来完成了这一点。

DWORD WINAPI ThreadProc( LPVOID lpParam )
{
// lpParam not used in this example
UNREFERENCED_PARAMETER(lpParam);
DWORD dwWaitResult; 
BOOL bContinue=TRUE;
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si,0,sizeof(si));
si.cb=sizeof(si);
while(bContinue)
{
// Try to enter the semaphore gate.
dwWaitResult = WaitForSingleObject( 
ghSemaphore,   // handle to semaphore
0L);           // zero-second time-out interval
CreateProcess("arbol.exe",NULL,NULL,NULL,0,0,NULL,NULL,&si,&pi);    
WaitForSingleObject(pi.hProcess,INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
switch (dwWaitResult) 
{ 
// The semaphore object was signaled.
case WAIT_OBJECT_0: 
// TODO: Perform task
printf("Thread %d: wait succeededn", GetCurrentThreadId());
bContinue=FALSE;            
// Simulate thread spending time on task
Sleep(5);
// Release the semaphore when task is finished
if (!ReleaseSemaphore( 
ghSemaphore,  // handle to semaphore
1,            // increase count by one
NULL) )       // not interested in previous count
{
printf("ReleaseSemaphore error: %dn", GetLastError());
}
break; 
// The semaphore was nonsignaled, so a time-out occurred.
case WAIT_TIMEOUT: 
printf("Thread %d: wait timed outn", GetCurrentThreadId());
break; 
}
}
return TRUE;
}

因此,尽管决定信号量填充的是线程,但在实际意义上,它是由进程句柄的完全执行和关闭来决定的。

但这看起来是解决这个问题的一种蹩脚的方法,我敢打赌,如果这些过程需要额外的东西,那么这样做可能会在未来产生问题。

我如何创建一个信号量,以便真正决定信号量填充的是进程?澄清一下,这将是一个可能的解决方案,我认为无论如何都不可能。

让我们考虑一下,您可以通过以下方式创建流程:

aThread[i] = CreateProcess( 
NULL,       // default security attributes
0,          // default stack size
(LPTHREAD_START_ROUTINE) ThreadProc, 
NULL,       // no thread function arguments
0,          // default creation flags
&ThreadID); // receive thread identifier

那么LPTHREAD_START_ROUTINE在其工作中是等效的,但对于进程来说是等效的。

信号应该支持Windows API中的进程间同步,但我找不到任何专门使用进程的示例,也不知道如何实现。

你知道如何实现我想要的吗?

谨致问候。

您想要一个命名的信号量。其中,每个进程通过创建具有相同名称的信号量来共享信号量。

创建一个命名信号量。和以前一样,但最后一个参数会得到一个传递给它的字符串:

HANDLE hSemaphore = CreateSemaphore(NULL, 
MAX_SEM_COUNT,
MAX_SEM_COUNT,
L"TheSemaphoreForMyApp");

启动后,子进程可以连接到同一个信号量,并通过使用OpenSemaphore获得它的句柄。

HANDLE hSemaphore = OpenSemaphore(EVENT_ALL_ACCESS, 
FALSE,
L"TheSemaphoreForMyApp");

您不必将字符串硬编码为信号量名称。父进程每次都可以创建一个唯一的名称,然后将该名称(例如命令行参数)传递给子进程。这将允许具有子进程的程序的多个实例进行协作。