Peter
Peter

Reputation: 337

WINAPI Event Object unexpected behaviour

I have 2 programs. The first program will open the second one and will also create 2 Event objects that will be used for synchronization. The second one (the one to be opened) will open those 2 Event objects. Both of the programs will run a for loop to simulate writing and reading operations from memory.

Program one:

    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);
    }

Program two:

    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);
    }

I would expect the output to be:

Wrote data to memory.
Read data from memory.
Wrote data to memory.
Read data from memory.
       ....

but the real output is something like:

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.
      ...

And at some point it just hangs, which would mean a deadlock. But I'm not sure how is this possible. Any help?

Upvotes: 0

Views: 393

Answers (1)

RbMm
RbMm

Reputation: 33706

for WaitForSingleObject - handle to the object (1-st parameter) must have the SYNCHRONIZE access right. otherwise api failed with ERROR_ACCESS_DENIED. but you call

write = OpenEvent(EVENT_MODIFY_STATE, false, "WRITE");

requested access not include SYNCHRONIZE which you need and include EVENT_MODIFY_STATE which you really not need in this code. so you need change code to

write = OpenEvent(SYNCHRONIZE, false, "WRITE");

also you not check result of any api call. if you do this - you just view that WaitForSingleObject(write, INFINITE); return WAIT_FAILED and GetLastError() == ERROR_ACCESS_DENIED.

also if you need ipc via this 2 events with child process - better create it unnamed and inherited, and pass it values via command line to child. if you want test only event work logic - more easy use separate thread instead new process. for this test code can look like:

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);
    }
}

interesting that early (before win 8.1) was EventPair object in windows, which was design for such task. but unknown reason it was removed

Upvotes: 2

Related Questions