我有 2 个程序。 第一个程序将打开第二个程序,还将创建 2 个用于同步的事件对象。 第二个(要打开的那个)将打开这 2 个事件对象。 这两个程序都会运行一个 for 循环来模拟从内存中写入和读取操作。
程序一:
read = CreateEvent(NULL, false, false, "READ");
write = CreateEvent(NULL, false, false, "WRITE");
CreateProcess("PATH_TO_EXE", NULL, NULL, NULL, FALSE, NULL, 0, NULL, &startupInfo, &processInformation);
for (int i = 1; i <= 100; i++)
{
printf("Wrote data to memory\n");
SetEvent(write);
WaitForSingleObject(read, INFINITE);
}
方案二:
HANDLE read, write;
read = OpenEvent(EVENT_MODIFY_STATE, false, "READ");
write = OpenEvent(EVENT_MODIFY_STATE, false, "WRITE");
for (int i = 1; i <= 100; i++)
{
WaitForSingleObject(write, INFINITE);
printf("Read data from memory.\n");
SetEvent(read);
}
我希望输出是:
Wrote data to memory.
Read data from memory.
Wrote data to memory.
Read data from memory.
....
但实际输出是这样的:
Wrote data to memory.
Read data from memory.
Read data from memory.
Read data from memory.
Read data from memory.
Read data from memory.
Read data from memory.
Read data from memory.
Wrote data to memory.
Read data from memory.
Wrote data to memory.
Wrote data to memory.
Read data from memory.
...
在某些时候它只是挂起,这意味着死锁。但我不确定这怎么可能。有帮助吗?
最佳答案
WaitForSingleObject
- 对象句柄(第一个参数)必须具有 SYNCHRONIZE
访问权限。否则 api 因 ERROR_ACCESS_DENIED
而失败。但是你调用
write = OpenEvent(EVENT_MODIFY_STATE, false, "WRITE");
请求的访问权限不包括您需要的SYNCHRONIZE
,并包括您在此代码中确实不需要的EVENT_MODIFY_STATE
。所以你需要将代码更改为
write = OpenEvent(SYNCHRONIZE, false, "WRITE");
您也不检查任何 api 调用的结果。如果您这样做 - 您只需查看 WaitForSingleObject(write, INFINITE);
返回 WAIT_FAILED
和 GetLastError() == ERROR_ACCESS_DENIED
。
另外,如果您需要通过这 2 个带有子进程的事件来使用 ipc - 最好创建未命名和继承的它,并通过命令行将其值传递给子进程。如果您只想测试事件工作逻辑 - 更容易使用单独的线程而不是新进程。此测试代码可能如下所示:
ULONG WINAPI child(void* p)
{
if (HANDLE read = OpenEvent(EVENT_MODIFY_STATE, false, L"READ"))
{
if (HANDLE write = OpenEvent(SYNCHRONIZE, false, L"WRITE"))
{
ULONG i = (ULONG)(ULONG_PTR)p;
do
{
if (WaitForSingleObject(write, INFINITE) == WAIT_FAILED){
DbgPrint("2:%u\n", GetLastError());
break;
}
DbgPrint("Read data from memory.\n");
if (!SetEvent(read)){
DbgPrint("3:%u\n", GetLastError());
break;
}
} while (--i);
CloseHandle(write);
}
CloseHandle(read);
}
return 0;
}
void bfg()
{
if (HANDLE read = CreateEvent(NULL, false, false, L"READ"))
{
if (HANDLE write = CreateEvent(NULL, false, false, L"WRITE"))
{
ULONG i = 16;
if (HANDLE hThread = CreateThread(0, 0, child, (PVOID)(ULONG_PTR)i, 0, 0))
{
do
{
DbgPrint("Wrote data to memory\n");
if (!SetEvent(write) || WaitForSingleObject(read, INFINITE) == WAIT_FAILED){
DbgPrint("1:%u\n", GetLastError());
break;
}
} while (--i);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
CloseHandle(write);
}
CloseHandle(read);
}
}
有趣的是,早期(在 win 8.1 之前)是 Windows 中的 EventPair 对象,它是为此类任务而设计的。但未知原因将其删除
关于c++ - WINAPI 事件对象意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53253441/