まつもと ゆきひろです

In message "[ruby-list:7472] socket"
    on 98/04/15, Wakou Aoyama <wakou / fsinet.or.jp> 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の部分を別のメソッド(関数)に分離して
も良いでしょう.
                                まつもと ゆきひろ /:|)