Неожиданное поведение объекта события WINAPI - PullRequest
0 голосов
/ 12 ноября 2018

У меня 2 программы. Первая программа откроет вторую, а также создаст 2 объекта Event, которые будут использоваться для синхронизации. Второй (который будет открыт) откроет эти 2 объекта Event. Обе программы будут запускать цикл 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.
      ...

И в какой-то момент он просто зависает, что означало бы тупик. Но я не уверен, как это возможно. Любая помощь?

1 Ответ

0 голосов
/ 12 ноября 2018

для WaitForSingleObject - дескриптор объекта (1-й параметр) должен иметь право доступа 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.

также, если вам нужен ipc через эти 2 события с дочерним процессом - лучше создайте его без имени и унаследованного и передайте его значения через командную строку дочернему процессу. если вы хотите проверить логику работы только с событиями - проще использовать отдельный поток вместо нового процесса. для этого теста код может выглядеть так:

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) был EventPair объект в Windows, который был разработан для такой задачи. но по неизвестной причине он был удален

...