【发布时间】:2017-04-27 18:04:35
【问题描述】:
我正在异步调用ReadDirectoryChangesW 以监视后台线程中的目录更改。
这是打开目录 (basePath) 并启动“阅读”线程的方式:
m_hDIR = CreateFileW(
basePath,
FILE_LIST_DIRECTORY | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
if (m_hDIR == INVALID_HANDLE_VALUE)
throw CrException(CrWin32ErrorString());
//Start reading changes in background thread
m_Callback = std::move(a_Callback);
m_Reading = true;
m_ReadThread = std::thread(&CrDirectoryWatcher::StartRead, this);
这是StartRead():(注意:m_Reading 是atomic<bool>)
void StartRead()
{
DWORD dwBytes = 0;
FILE_NOTIFY_INFORMATION fni{0};
OVERLAPPED o{0};
//Be sure to set the hEvent member of the OVERLAPPED structure to a unique event.
o.hEvent = CreateEvent(0, 0, 0, 0);
while(m_Reading)
{
if (!ReadDirectoryChangesW(m_hDIR,
&fni, sizeof(fni),
TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE,
&dwBytes, &o, NULL))
{
CrAssert(0, CrWin32ErrorString());
}
if (!GetOverlappedResult(m_hDIR, &o, &dwBytes, FALSE))
CrAssert(0, CrWin32ErrorString());
if (fni.Action != 0)
{
std::wstring fileName(fni.FileName, fni.FileNameLength);
m_Callback(fileName);
fni.Action = 0;
}
}
}
基本上,我在每一帧都“轮询”新的变化。
现在,当我调用 GetOverlappedResult() 时,它会失败并产生以下错误:
重叠的 I/O 事件未处于信号状态。
我错过了什么吗? ReadDirectoryChangesW 是否意味着每个“滴答”都被称为?或者只是在检测到新的变化时?
注意:当我省略 OVERLAPPED 结构(和 GetOverlappedResult)时,它可以工作,但会阻塞线程,直到读取更改。这会阻止我的应用程序正确终止。 (即我无法加入线程)
【问题讨论】:
-
您尝试过
if (!GetOverlappedResult(m_hDIR, &o, &dwBytes, TRUE))- 如果我正确阅读了GetOverlappedResultfunction doc,那应该会阻塞您的线程,直到真正有东西要阅读。 -
在操作完成之前您无法获得结果。这允许您做其他事情,但基本问题是您没有做其他事情。代码坚持立即得到结果。所以使用重叠 I/O 没有任何意义。查看 RegisterWaitForSingleObject() 以(可能)使其更像您的意图。或者使用工作线程。
-
真的是同步调用 ReadDirectoryChangesW。在 OVERLAPPED 中使用事件最糟糕的方式 - 比较 IOCP 和 apc
-
@PhilBrubaker 但这会导致线程“无法连接”,对吧?
-
@HansPassant RegisterWaitForSingleObject() 是否与 OVERLAPPED 一起使用?因为没有提供结构 ReadDirectoryChangesW 块。
标签: c++ windows multithreading winapi