【问题标题】:ReadDirectoryChangesW Asynchronous Completion routine called after I close the handle关闭句柄后调用的 ReadDirectoryChangesW 异步完成例程
【发布时间】:2019-12-06 19:03:49
【问题描述】:

我正在使用ReadDirectoryChangesW 来监视目录中文件何时发生更改。我正在使用带有完成例程函数的异步版本(根据文档)。

在我希望停止监视文件夹之前一切正常。

为了停止监控,我调用了Close 函数。

问题是我仍然收到最后一个通知,但到那时我已经销毁了我的 LPOVERLAPPED 值。

我怎样才能停止ReadDirectoryChangesW 并防止我的MyCompletionRoutine 函数被调用。

// get the handle    
_handle = CreateFileW( ... )

void Read()
{
  ...
  ReadDirectoryChangesW( _handle, ..., &MyCompletionRoutine );
  ...
}

void Close()
{
  ::CancelIo(_handle );           
  ::CloseHandle(_handle );
}

void __stdcall MyCompletionRoutine (
    const unsigned long dwErrorCode,
    const unsigned long dwNumberOfBytesTransfered,
    _OVERLAPPED* lpOverlapped )
{
  // ... do stuff and start a read again
  Read();
}

在上面的代码中,我可能调用了Read,但我想在调用MyCompletionRoutine 之前停止。

不确定这是否有帮助,但我收到的错误消息是 317

【问题讨论】:

  • 你猛拉地垫,它必须完成。在那之前您不能安全地删除 OVERLAPPED,可能的内存损坏很难诊断。
  • 对不起,我不明白你的意思,什么布尔变量?完成例程是一个静态函数,LPOVERLAPPED 不再有用,(那时它是未定义的)。
  • 只有在 I/O 完成后才能删除 lpOverlapped 指向的内存 - 这意味着如果 ReadDirectoryChangesW 返回 false 或内部回调
  • 是的,我明白了,但问题是在我关闭句柄之后(在读取和回调之间),我不再需要任何消息。例如,如果我从未收到回电怎么办?我不能永远保持 lpOverlapped 希望它会被调用。
  • @FFMG 如果 i/o 启动正常 (ReadDirectoryChangesW ) 返回 true - 你保证它会完成。它在文件上调用 CloseHandleCancelIo 后完成。当 i/o 完成时 - apc 将排队到您的线程(因为您使用 apc 完成)。但只有当您执行警报等待或调用 NtTestAlert 时才会调用用户模式 ​​apc。问题是您不了解这里的内部对象管理。免费/删除的内容和时间。

标签: winapi readdirectorychangesw


【解决方案1】:

您将关闭您的HANDLE 并过早释放您的OVERLAPPED

CancelIo()(以及它的跨线程兄弟CancelIoEx())只需将活动的 I/O 操作标记为已取消然后退出,但您仍然需要真正等待这些操作完全完成,然后才能释放它们OVERLAPPED.

如果一个操作在完成它的工作之前注意到取消,它将停止它的工作并报告一个错误代码ERROR_OPERATION_ABORTED的完成,否则它将正常完成它的工作并用适当的错误代码报告一个完成。

在调用CancelIo/Ex()之后,你需要继续等待并处理完成的操作,直到没有更多的操作可以等待。

也就是说,MyCompletionRoutine()确实可以在调用CancelIo()之后调用,并且需要在再次调用Read()之前检查ERROR_OPERATION_ABORTED。如果在调用 CancelIo() 时有正在进行的读取,则需要等待该读取完成。

【讨论】:

  • 谢谢,我添加了SleepEx(...) 以及一个标记之后调用CancelIo,我终于得到ERROR_OPERATION_ABORTED
  • CancelIo 是异步的 - 严格来说这是错误的。 CancelIo wait 直到所有活动的 I/O 请求都将完成(这是真实的并且在现代版本中)但是另一个问题 - 当用户模式收到有关此的通知时。如果 APC 完成 - apc(MyCompletionRoutine) 只能在几个 api 调用(alertable wait 或 NtTestAlert)内调用,所以它总是会在 CancelIo(或 CloseHandle 调用)之后调用,但前提是应用程序可以警报在此之后等待(或致电NtTestAlert
猜你喜欢
  • 1970-01-01
  • 2016-08-13
  • 1970-01-01
  • 2016-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-10
相关资源
最近更新 更多