我需要实现一个使用信号量将打开的记事本窗口数量限制为10的程序。我在WM_INITDIALOG中创建了一个信号量
semafor = CreateSemaphore(0, 1, 10, "semaphore");
每次我点击按钮打开一个新窗口,我打开那个信号量。然而,它并没有阻止我打开超过10个窗口。
当我点击对话框中的按钮打开一个新窗口时,这是我的代码:
case WM_COMMAND:
switch (LOWORD(wParam)) {
case ID_OK:
semafor = OpenSemaphore(SEMAPHORE_ALL_ACCESS, TRUE, "semaphore");
if (semafor == NULL) {
printf("Eroare deschidere semafor empty: %d \n", GetLastError());
ExitProcess(1);
}
BOOL b = CreateProcess("C:\\Windows\\System32\\notepad.exe",
NULL, NULL, NULL, TRUE, 0, NULL, NULL,
&si, &pi);
process[++i] = GetCurrentProcess();
if (b) {
dwWaitForChild = WaitForInputIdle(pi.hProcess, 2000);
switch (dwWaitForChild) {
case 0:
printf("Procesul fiu este ready!\n");
break;
case WAIT_TIMEOUT:
printf("Au trecut 2 sec. si procesul fiu nu este ready!\n");
break;
case 0xFFFFFFFF:
printf("Eroare!\n");
break;
}
WaitForMultipleObjects(i, process, TRUE, INFINITE);
iRasp = MessageBox(NULL, "Terminam procesul fiu?", "Atentie!", MB_YESNO);
if (iRasp == IDYES) {
if (TerminateProcess(pi.hProcess, 2)) {
DWORD dwP;
GetExitCodeProcess(pi.hProcess, &dwP);
printf("Codul de terminare al procesului fiu: %d\n", dwP);
ReleaseSemaphore(semafor, 1, NULL);
CloseHandle(pi.hProcess);
printf("\nProcesul fiu a fost terminat cu succes\n");
}
else {
//tiparim mesajul de eroare
TCHAR buffer[80];
LPVOID lpMsgBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0, NULL);
wsprintf(buffer, "TerminateProcess() a esuat cu eroarea %d: %s",
dw, lpMsgBuf);
MessageBox(NULL, buffer, "Eroare!", MB_OK);
LocalFree(lpMsgBuf);
}
} // rasp YES
}
else
printf("Eroare la crearea procesului fiu!\n");
return TRUE;
}
break;
}
return FALSE;
}
答案 0 :(得分:2)
你不会在信号量上等待(或信号量逻辑中的P)。
检查winapi example如何使用信号量。在他们的示例中,他们使用WaitForSingleObject
。你只使用OpenSemaphore
只给你信号量句柄,这样你就可以在多个进程中使用它,如果你想减少它的值,那么你需要实际等待它,并在它为0时等待/超时。
在打开信号量之后和尝试打开记事本实例之前,你应该做这样的事情:
// Try to enter the semaphore gate.
dwWaitResult = WaitForSingleObject(
ghSemaphore, // handle to semaphore
0L); // zero-second time-out interval
答案 1 :(得分:0)
你滥用信号量。一次创建信号量并重复使用它,不要一遍又一遍地重新打开它。但是,更重要的是,您必须等待信号量,例如使用WaitForSingleObject()
,减少其计数器,然后使用ReleaseSeamphore()
释放它以增加其计数器。信号量的状态在其计数器大于0时发出信号,在0时没有信号。
因此,您需要创建初始计数为10的信号量,然后在每次要创建新进程时等待它。如果等待失败,则已经有太多进程在运行。否则,如果等待成功,则计数器已递减,因此创建新进程,然后在进程结束时递增计数器。
然而,话虽如此,在您展示的代码的上下文中,您的信号量是完全无用的。您希望使用信号量来控制记事本的运行实例数,但是一旦启动1个实例,您就会尝试(错误地,我可能会添加)来阻止您的代码,直到该实例退出。所以你永远不能一次运行多个实例,使信号量无用。您可以运行超过1的事实可能是由于代码中的错误(您正在等待错误的进程句柄!)。不要使用阻塞等待。让系统在每个衍生过程结束时通知您。
在代码中使用信号量的正确方法看起来更像是这样:
const UINT WM_PROCESS_ENDED = WM_APP + 1;
const int MAX_PROCESSES = 10;
typedef struct procInfo
{
HANDLE hProcess;
HANDLE hWait;
} procInfo;
HANDLE semafor = NULL;
procInfo process[MAX_PROCESSES] = {};
int numProcesses = 0;
HWND hwndDialog;
...
VOID CALLBACK ProcessEnded(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
PostMessage(hwndDialog, WM_PROCESS_ENDED, 0, (LPARAM)lpParameter);
}
...
case WM_INITDIALOG:
{
hwndDialog = hwnd;
semafor = CreateSemaphore(0, MAX_PROCESSES, MAX_PROCESSES, NULL);
if (semafor == NULL)
{
printf("Eroare deschidere semafor empty: %d \n", GetLastError());
ExitProcess(1);
}
break;
}
case WM_DESTROY:
{
for (int i = 0; i < numProcesses; ++i)
{
UnregisterWaitEx(process[i].hWait, INVALID_HANDLE_VALUE);
TerminateProcess(process[i].hProcess, 2);
CloseHandle(process[i].hProcess);
}
CloseHandle(semafor);
semafor = NULL;
hwndDialog = NULL;
break;
}
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_OK:
{
if (WaitForSingleObject(semafor, 0) != WAIT_OBJECT_0)
{
// too many instances running...
break;
}
if (!CreateProcess("C:\\Windows\\System32\\notepad.exe",
NULL, NULL, NULL, TRUE, 0, NULL, NULL,
&si, &pi))
{
printf("Eroare la crearea procesului fiu!\n");
ReleaseSemaphore(semafor, 1, NULL);
break;
}
CloseHandle(pi.hThread);
dwWaitForChild = WaitForInputIdle(pi.hProcess, 2000);
switch (dwWaitForChild)
{
case 0:
printf("Procesul fiu este ready!\n");
break;
case WAIT_TIMEOUT:
printf("Au trecut 2 sec. si procesul fiu nu este ready!\n");
break;
case WAIT_FAILED:
printf("Eroare!\n");
break;
}
procInfo info;
info.hProcess = pi.hProcess;
if (!RegisterWaitForSingleObject(&info.hWait, pi.hProcess, &ProcessEnded, pi.hProcess, INFINITE, WT_EXECUTELONGFUNCTION | WT_EXECUTEONLYONCE))
{
TerminateProcess(pi.hProcess, 2);
ReleaseSemaphore(semafor, 1, NULL);
break;
}
process[numProcesses++] = info;
}
}
break;
}
case WM_PROCESS_ENDED:
{
HANDLE hProcess = (HANDLE)lParam;
for (int i = 0; i < numProcesses; ++i)
{
if (process[i].hProcess == hProcess)
{
UnregisterWait(process[i].hWait);
for (int j = i + 1; j < numProcesses; ++j)
process[j-1] = process[j];
--numProcesses;
break;
}
}
CloseHandle(hProcess);
ReleaseSemaphore(semafor, 1, NULL);
}
在这种情况下,你可以完全摆脱信号量,因为你已经有了自己的计数器:
const UINT WM_PROCESS_ENDED = WM_APP + 1;
const int MAX_PROCESSES = 10;
typedef struct procInfo
{
HANDLE hProcess;
HANDLE hWait;
} procInfo;
procInfo process[MAX_PROCESSES] = {};
int numProcesses = 0;
HWND hwndDialog;
...
VOID CALLBACK ProcessEnded(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
PostMessage(hwndDialog, WM_PROCESS_ENDED, 0, (LPARAM)lpParameter);
}
...
case WM_INITDIALOG:
{
hwndDialog = hwnd;
break;
}
case WM_DESTROY:
{
for (int i = 0; i < numProcesses; ++i)
{
UnregisterWaitEx(wait[i], INVALID_HANDLE_VALUE);
TerminateProcess(process[i], 2);
CloseHandle(process[i]);
}
hwndDialog = NULL;
break;
}
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_OK:
{
if (numProcesses >= MAX_PROCESSES)
{
// too many instances running...
break;
}
if (!CreateProcess("C:\\Windows\\System32\\notepad.exe",
NULL, NULL, NULL, TRUE, 0, NULL, NULL,
&si, &pi))
{
printf("Eroare la crearea procesului fiu!\n");
break;
}
CloseHandle(pi.hThread);
dwWaitForChild = WaitForInputIdle(pi.hProcess, 2000);
switch (dwWaitForChild)
{
case 0:
printf("Procesul fiu este ready!\n");
break;
case WAIT_TIMEOUT:
printf("Au trecut 2 sec. si procesul fiu nu este ready!\n");
break;
case WAIT_FAILED:
printf("Eroare!\n");
break;
}
procInfo info;
info.hProcess = pi.hProcess;
if (!RegisterWaitForSingleObject(&info.hWait, pi.hProcess, &ProcessEnded, pi.hProcess, INFINITE, WT_EXECUTELONGFUNCTION | WT_EXECUTEONLYONCE))
{
TerminateProcess(pi.hProcess, 2);
break;
}
process[numProcesses++] = info;
}
}
break;
}
case WM_PROCESS_ENDED:
{
HANDLE hProcess = (HANDLE)lParam;
for (int i = 0; i < numProcesses; ++i)
{
if (process[i].hProcess == hProcess)
{
UnregisterWait(process[i].hWait);
for (int j = i + 1; j < numProcesses; ++j)
process[j-1] = process[j];
--numProcesses;
break;
}
}
CloseHandle(hProcess);
}