2008-05-23

VistaでやっとまともにサポートされたI/Oのキャンセル機能

Win32 I/O Cancellation Support in Windows Vista
via ファイル I/O でブロックされているスレッドを殺したくなったらどうするか?

最近、technical articleでkanji scriptsをreadするのがtediusなので、リンクは英語の記事に貼った。

今まで、一度もCancelIoを使う機会に恵まれなかったので、知らなかったのだが、I/Oのまともなキャンセル機能というのは、Vistaになって初めてサポートされたらしい。ドライバが対応していればの話だが。CancelIoでキャンセルできないI/Oは以下の通り。

I/O operations issued for the file handle by other threads;
  え、マジで?
Specific I/O operations;
  いや、具体的に頼む。
Synchronous I/O operations, since they (by definition) block in the operating system;
  え、できなかったの?
I/O issued to a completion port or associated with an IOSB range.
  おいおい、完了ポート未対応だったのかよ

Vista以降は、CopyFileなどの一部複雑なAPIを除き、ほとんどのI/O操作をキャンセルできる。WalkTreeというAPIを知らず、探しても出てこないのだが、これはVBか.netか何かのライブラリなのだろうか。

あるファイルハンドルへの、すべてのスレッドからの非同期I/Oをキャンセルしたい場合は、CancelIoExを使い、OVERLAPPED構造体へのポインタは、NULLを指定しておく。こうすれば、現在のプロセスのすべてのスレッドから行われた操作がキャンセルできる

同期I/Oをキャンセルしたい場合は、そのファイルハンドルに対して、CancelSynchronousIoを呼び出せばよい。

ただし、これらのキャンセルを用いる場合は、Raceを考慮しなければならない。例えばすべてのスレッドの非同期IOをキャンセルしたいとしても、スレッドごとに順次キャンセルしていくので、すでにキャンセルし終えたスレッドが、別のIO操作をするかもしれない。同期IOのキャンセルに関しては、ある処理がなかなか終わらないので、他のスレッドからキャンセルしようとしたが、まさにキャンセルしようとした瞬間に処理が終わり、新しく始めた別の処理をキャンセルしてしまうこともある。

No comments: