为什么即使在显式 ResetEvent 调用后我也不能重用事件?
Why can't I reuse an event even after explicit ResetEvent call?
我想查看对文件所做的更改(我正在等待的事件是更改内容事件,即上次修改日期已更新)
我有这样的代码(实际代码的最小化示例)
我希望 while 循环的每次迭代都会重置事件并可以再次触发,但这并没有发生
为什么它只触发一次更改事件?
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);
}
}
}
因为那不是 ReadDirectoryChanges
的工作方式。它不会持续向您发送更改。它会向您发送一批更改。你处理它们。您再次调用该函数以告诉系统您需要更多更改。
我在这里找到了函数的正确用法示例:https://gist.github.com/nickav/a57009d4fcc3b527ed0f5c9cf30618f8
一些旁注:
- 您没有检查
ReadDirectoryChanges
是否成功。这是不好的;如果失败,您将永远挂在 Wait 呼叫上。
- 您没有 zero-initialize
OVERLAPPED
结构。
- 您将事件创建为 auto-reset 事件(第二个参数是
FALSE
)。 ResetEvent
对这样的事件什么都不做。
- 您添加到向量中的所有事件句柄都是同一个事件对象。您只是重复传递给
WaitForMultipleObjects
的同一事件的 ever-growing 列表。这充其量什么也不做,但最终会失败,因为 WFMO
不允许超过 MAXIMUM_WAIT_OBJECTS
个句柄,而且这个数字相当低(我认为是 32)。
- 您可能希望在您打开的目录上使用更宽松的共享模式。
我想查看对文件所做的更改(我正在等待的事件是更改内容事件,即上次修改日期已更新)
我有这样的代码(实际代码的最小化示例)
我希望 while 循环的每次迭代都会重置事件并可以再次触发,但这并没有发生
为什么它只触发一次更改事件?
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);
}
}
}
因为那不是 ReadDirectoryChanges
的工作方式。它不会持续向您发送更改。它会向您发送一批更改。你处理它们。您再次调用该函数以告诉系统您需要更多更改。
我在这里找到了函数的正确用法示例:https://gist.github.com/nickav/a57009d4fcc3b527ed0f5c9cf30618f8
一些旁注:
- 您没有检查
ReadDirectoryChanges
是否成功。这是不好的;如果失败,您将永远挂在 Wait 呼叫上。 - 您没有 zero-initialize
OVERLAPPED
结构。 - 您将事件创建为 auto-reset 事件(第二个参数是
FALSE
)。ResetEvent
对这样的事件什么都不做。 - 您添加到向量中的所有事件句柄都是同一个事件对象。您只是重复传递给
WaitForMultipleObjects
的同一事件的 ever-growing 列表。这充其量什么也不做,但最终会失败,因为WFMO
不允许超过MAXIMUM_WAIT_OBJECTS
个句柄,而且这个数字相当低(我认为是 32)。 - 您可能希望在您打开的目录上使用更宽松的共享模式。