まつもと ゆきひろです
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の部分を別のメソッド(関数)に分離して
も良いでしょう.
まつもと ゆきひろ /:|)