memo/20070412
created 2007-04-12 modified 2007-04-26
アレ(Z)のイベント処理を、Windowsでどう書くか、また同一概念でUnixでもWindowsでも書けるようにライブラリを設計するにはどうするか、という話のつづき。
メインループをライブラリが持つという概念はいいとして、Windowsの重複I/Oで代用するには(バッファポインタと長さを先に渡す必要から)、Unix側をWindowsにあわせる(I/O関数を先に発行して結果をコールバックしてもらう)必要がある、と思っていた。
この方式だと、I/O関数の数だけイベント登録のクチを用意してやる必要があって大変(add_readとadd_writeだけじゃなくて、add_read, add_accept, add_write, add_connect, ... を作る必要がある )。
実際それでもう作ってしまったわけだが...
glibの最新を見たら、Unix方式(selectを先に発行してI/O関数で待たされなことを確認してからI/O関数を呼ぶ)にWindowsをあわせるやりかたで実装されているっぽい(それが実現可能であるっぽいということ)。
どうやらopenしたらライブラリが別スレッドを作って、ブロッキングでreadを発行するとか。それで、そのバッファはライブラリが管理するバッファで、ユーザには直接読み書きさせず、関数を経由させる、と。
やっぱりあれだ。薄々思ってたとおり、Unixでいうioレイヤ(int fdを管理して、オープンしてるやつの配列をもってたりするらしいあのへん)がWindowsにはないから、そこをライブラリが作ってやるってことだと思われ。
だけどそうすると1プロセス64スレッド問題にぶつからないのかな?
ていうかもしかして、重複I/Oって実は内部で別スレ起動してる?いやいや、DirectX風の考え方(ハード実装者とソフト実装者の間を取り持つ)でやってくれてると信じたい...
ともあれ重複I/Oにインタフェースをあわせる方式でUnix側でも組めたし、Windows側では重複I/Oを使って別スレを使ってないからか64を超えるイベントを同時に処理できてるし、まぁこれはこれでよかろう。
うーん、でもアレだ。忘れてた。
少なくとも.Netでは、重複I/Oのコールバックは別スレッドでした。
だからそこの部分(発火済みイベントリストにつなぎかえるところ)だけ自前でスレッド排他したことでした。
どうやら検索で飛んできたかたがひとりおられたみたいですが...
WaitForMultipleObjects ではなく、WaitForSingleObject (相当の.Net処理)でいけますた。「発火済みイベントリストに追加したよ」とメインスレッドに通知すると。
あと、少なくとも私の開発環境では、.Net の Select() は、誰も読み書きOKになってないのにブロック解除してくれやがる(Select()が帰ってきてしまう)というとんでもない動作をしていて、無駄にCPU使用率が100%になっていました。
重複I/Oを使い、Select() をやめたら解消しました。