From: matz@... (Yukihiro Matsumoto) Date: 1998-04-15T12:44:40+09:00 Subject: [ruby-list:7490] Re: socket まつもと ゆきひろです In message "[ruby-list:7472] socket" on 98/04/15, Wakou Aoyama writes: |青山です。 | |ruby-1.1b_10 の(07-09 のどれかかも)の socket の動きが変です。 あー,ソケットに本質的な変更は加えていませんが,なんとなく心 辺りがあります.これはローカル変数のバグフィックスのせいでは ないかと思います. つまり, |loop do | sock = port.accept # stand by for accept | | Thread.start do # divide the work | case http_header_analyze(sock) この部分での変数sockですが,これは全体(全てのスレッドで)共有 されます.つまり,sockの値を変更するとそれは全てのスレッドに 対して有効です.ですから,次のacceptでsockの値が変ってしまっ たわけですね. どうも1.1b6以前ではローカル変数処理のバグである種のローカル 変数が勝手にスレッド毎に独立した値を持つ時があったようです (未確認だけど,多分).1.1b7周辺でローカル変数の動作の部分に 修正を加えたので,その時に直ったのでしょう.この挙動はバグで す.この挙動に依存したプログラムは今後は正常に動作しません. で,対策ですが,スレッド毎に独立したローカル変数を持つには * スレッドブロック(startで指定したブロック)の中で初出の変 数を使う * スレッド内でメソッドを呼んでそのローカル変数を使う という方法があります. 前者は一種のイディオムで「ローカル変数はメソッドの先頭で初期 化すべし」という『ローカル変数のオキテ』の例外になります. 問題のプログラムを書き換えるとこうなります. |loop do | s = port.accept # stand by for accept | | Thread.start do # divide the work sock = s # copy to thread-local variable | case http_header_analyze(sock) # sockは外側で代入されていないとします. 一見無駄な代入のように見える,sock = s ですが,スレッド毎の 変数を用意する目的を果たしています. またはstart以降のdo..endの部分を別のメソッド(関数)に分離して も良いでしょう. まつもと ゆきひろ /:|)