丁稚な日々

Rubyで遊んだ日々の記録。あくまで著者視点の私的な記録なので、正確さを求めないように。
Rubyと関係ない話題にはその旨注記しているはず。なので、一見関係無いように見える話題もどこかで関係あるのかもしれません。または、注記の書き忘れかもしれません...

[直前] [最新] [直後] [Top]

Jul.17,2008 (Thu)

Revision: 1.1 (Jul.17,2008 11:56)

[mswin32] blocking I/O

_ 最近重視している問題をまとめてみます。

  • 1.9では、rubyスレッドはそれぞれ固有のnativeスレッドと結びついている
  • とはいえ、rubyスレッドは並列に実行されるわけではなく、あるrubyスレッドが動いている間はその他のrubyスレッドは実行を中断させられている
  • 各スレッドはタイムスライスを割り当てられて順次実行される
  • ただし、並列に実行してかまわない処理については、明示的にその処理をblocking regionという区間に区切ることによって、他のスレッドと同時に実行することができる
  • 具体的には、I/O処理など時間がかかる処理を行う場合に、そうした処理をblocking regionに入れることになる

ここまではいいですね。
で、

  • blocking regionから抜ける条件は、処理が終了するか、外部からの割り込み(Thread#killされるとか)が発生したときか、である
  • pthreadなプラットフォームでは、具体的にはこれはスレッドへのシグナル送信によって実現されている
  • pthreadのシグナルは当然対象スレッドの実行中の処理の中で拾われて、適当に処理されることが期待できる
  • win32では割り込み監視イベントをセットする
  • win32の場合は対象スレッドが自発的にそのイベントを見るまで割り込みが発生していることがそのスレッドに伝わらない
  • よって、単一の処理(API呼び出しとか)で時間がかかる場合はそのイベントを見るタイミングがないため、処理を中断してblocking regionを抜けることができない

というのが、現在着目している問題です。

_ 対策はいくつか考えられます。

  • 時間がかかる処理というのはどうせI/Oなんだから、割り込みをかけるスレッドからCancelIoEx()なりCancelSynchronousIo()を実行すればいいじゃない
    → どっちもVista以降のみです><
  • 対象スレッドをぶち殺せばいいじゃない
    → そのスレッドが解放が必要なリソースを使ってたら困るでしょ!
  • 対象スレッドに構造化例外を投げればどうだろう?
    → 他スレッドに例外を投げることはできません><
  • SetThreadContext()で対象のスレッドのEIPを書き換えればどんな処理でも挿入できるよ
    → API実行中はカーネルコードなのでSetThreadContext()は機能しません...
  • じゃあ、I/Oに関しては、overlapped I/Oを使ってI/O処理と割り込み監視イベントをWaitForMultipleObjects()で待てばいいんじゃね?
    → やっぱそれしかないよねえ...

_ というわけで、overlapped I/Oについてわかってることを確認しておきましょう。

  • Win9xのoverlapped I/Oは制限がきつい
    → まあ、それは諦めてもらいましょう
  • 名無しパイプはoverlappedできないので名前を付けないといけない
    → これはめんどくさいけどしかたない
  • socketは(winsock2なら)デフォルトでoverlapped可能
    → すばらしい!
  • ファイルなどはCreateFile()時にoverlappedフラグを立てないとダメ
    → すばらしくない!
  • MSVCRTの各関数はoverlapped対応してないので全部自前で置き換えないといけない
    → 作業量が...
  • read()/write()を置き換えるなら、当然テキストモード対応を忘れないように
    → 勘弁して...
  • ところでVC++8以降ではread()/write()にUTF-8/UTF-16対応というのが入ったのでそれも考慮して再実装しないといけない
    → だめだもうだめだ

_ あまりにも作業量が膨大であることが容易に想像されるわけですが、どうしたもんですかねえ。

Jul.18,2008 (Fri)

Revision: 1.2 (Jul.18,2008 20:30)

[mswin32] blocking I/O

_ とりあえず、socketにはtextmode問題がなく(*1)、かつ、Win9xでもoverlapped I/O処理が可能なので、recv, recvfrom, send, sendtoで実装して実験してみました。
首尾は上々、と思ったのですが、test/socket/test_nonblocking.rbが固まることを発見。
混ぜるな危険、ってやつかなあ。困った困った。

_ まあ、それはそれとして、textmode問題はやっぱuniversal newlineを実装することによって抜本的な解決をはかりたいところ。
VC++8のUTF-8/UTF-16対応はこの際無視ですな。rubyの中から以外で使うわけじゃないし。

_ とりあえず、nonblockingの際は従来同様の処理を行うようにして問題は回避したのでcommit。

付記

(*1) textmode問題がなく
デフォルトでbinmodeなので。


被捕捉アンテナ類
[Ant] [Antenna-Julia] [Rabbit's Antenna] [Ruby hotlinks]