c++ - WINAPI 事件对象意外行为

标签 c++ winapi process synchronization deadlock

我有 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_FAILEDGetLastError() == 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/

相关文章:

java - 如何在 Java 中检索正在运行的进程的工作目录?

c# - 多任务环境中的流程执行

java - 使用编码参数将 PdfToText 作为 Java 进程运行

c++ - CPU 光线转换

c++ - OpenGL - 绘制存储在 VBO 中的大量信息

c++ - 如何在 Qt 5 中写入和读取 QResource 文件?

c++ - main() 中下面 'i' 的类型。为什么是int&?

c - 通过第三方插件在我的应用程序中实现绘图的更好方法是什么?

c++ - 在 Windows 中获取替代文件名

c - Win32 匿名管道在首次读取后损坏