Home > front end >  Why can't I reuse an event even after explicit ResetEvent call?
Why can't I reuse an event even after explicit ResetEvent call?

Time:02-12

I want to watch for changes done with a file (the event i'm waiting for is change contents event, i.e. last modified date is updated)

I have a code like this (minimalized example of actual code) I expect that each iteration of the while loop the event gets reset and is available to be fired again but that doesn't happen
Why it fires change event only once?

int main()
{
    const wchar_t *dir_path = L"C:\\Users\\IC\\AppData\\Roaming\\JetBrains\\CLion2021.3\\scratches\\";

    HANDLE hDir = ::CreateFileW(
        dir_path,
        FILE_LIST_DIRECTORY,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
        NULL
    );

    FILE_NOTIFY_INFORMATION fni;
    OVERLAPPED overlapped;
    overlapped.hEvent = ::CreateEventA(NULL, FALSE, FALSE, NULL);

    ::ReadDirectoryChangesW(
        hDir,
        &fni,
        sizeof(fni),
        TRUE,
        FILE_NOTIFY_CHANGE_LAST_WRITE,
        NULL,
        &overlapped,
        NULL
    );

    while (true)
    {
        std::vector<HANDLE> all_job_event_handles;
        if (::ResetEvent(overlapped.hEvent) == FALSE)
        {
            printf("ResetEvent failed\n");
            fflush(stdout);
            return 1;
        }
        all_job_event_handles.push_back(overlapped.hEvent);

        DWORD result = ::WaitForMultipleObjects(all_job_event_handles.size(), all_job_event_handles.data(), FALSE, INFINITE);
        if (result == WAIT_FAILED)
        {
            printf("WaitForMultipleObjects failed\n");
            fflush(stdout);
            return 1;
        }

        if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0   all_job_event_handles.size())
        {
            printf("file changed\n");
            fflush(stdout);
        }
    }
}

CodePudding user response:

Because that's just not how ReadDirectoryChanges works. It doesn't continuously send you changes. It sends you one batch of changes. You process them. You call the function again to tell the system that you want more changes.

I found a correct usage example of the function here: https://gist.github.com/nickav/a57009d4fcc3b527ed0f5c9cf30618f8

Some side notes:

  • You don't check whether ReadDirectoryChanges succeeds. This is bad; if it failed, you will hang on the Wait call forever.
  • You don't zero-initialize the OVERLAPPED structure.
  • You create the event as an auto-reset event (second parameter is FALSE). ResetEvent on such an event does nothing.
  • All the event handles you add into your vector are the same event object. You just have an ever-growing list of the same event repeatedly that you pass to WaitForMultipleObjects. This does nothing at best, but will eventually fail because WFMO doesn't allow more than MAXIMUM_WAIT_OBJECTS handles, and this number is fairly low (32, I think).
  • You probably want a more permissive share mode on the directory you open.
  • Related