I/O Completion Port
I/O Completion Port(I/O完了ポート)すごいっす。これまじすごいっす
いやなんかこれが言いたくて未来日記みたいになってますよorz
IOCPは非同期I/Oに使う仕組みなのです。
まず、CreateIoCompletionPortで完了ポートを作成しデバイス系のハンドル
(ファイルハンドルやソケット)を関連付けます。
またあらかじめスレッドをいくつか動作させておいてGetQueuedCompletionStatusを呼び出しておきます。
GetQueuedCompletionStatusを呼び出したスレッドはそこで停止したままなのですが
関連付けされたデバイスのI/O処理が終了するとGetQueuedCompletionStatusから戻ってきてくれるのです。
そこで何かしらの処理をしてでGetQueuedCompletionStatusを再び呼び出し待機する
といったループ処理を行います。
今までのよくあるパターンでは完了するとコールバック関数が呼ばれるとかでした
でもIOCPの場合はスレッドプールのスレッドが解放されるといった仕組みになってます。
この解放はdeleteじゃなくてresumeのほう
んで、何がすごいっていうのかといいますと完了ポートを作成するときの
CreateIoCompletionPortの引数で指定できるNumberOfConcurrentThreadsがすごいのです。
完了ポートはWindowsのシステムが
GetQueuedCompletionStatusを呼び出して待機しているスレッドの数
GetQueuedCompletionStatusから解放されてちゃんと働いているスレッドの数
GetQueuedCompletionStatusから解放されたけど一時停止してるスレッドの数
を数えてます。
NumberOfConcurrentThreadsはGetQueuedCompletionStatusから解放されて
ちゃんと働いているスレッドの数を指定してるのです。
たとえばCPUのコア以上のスレッドをむやみに動かしてもタスクスケジューリングで
無駄なコストがかかるだけですから
できれば常に稼動しているスレッドの数がCPUの数なのがパフォーマンス的に優位です。
これを実現してくれます。
GetQueuedCompletionStatusでたくさんのスレッドが待機していても
大量のI/O処理が一度に完了してもNumberOfConcurrentThreads以上のスレッドを解放しようとしません。
もし解放しているスレッドがGetQueuedCompletionStatusを呼び出す前に
たとえばクリティカルセクションなんかの同期オブジェクトで一時停止した場合は
ちゃんと働いているスレッドの数が1減りますから
GetQueuedCompletionStatusで待機中のスレッドを解放します。
その後クリティカルセクション待機中のスレッドが復帰して働きだした場合
NumberOfConcurrentThreadsで指定した最大数を越すことになりますが
基本的にはNumberOfConcurrentThreadsを目指してOS君はがんばります。