synchronized文とセマフォ待ち行列と愚痴と言い訳

@ 問題の発端
ポエニーで、通信だけは速く動かして、あとは限界に達するまでは、内部で受信コマンドをキューに貯めながら処理していこうと思って、コネクション管理タスクをディレイなしでフル稼働させたら、他のタスクがコネクションテーブル(コネクションの配列のようなもの)に一切アクセスできなくなった。

で、前までは大丈夫だったのになぜだろと思ったら、前は自前のセマフォクラスでロックしていたのをGCがなぜかメモリリークするからと、synchronized文に変えたんだった。しかたなく、また適度にディレイを入れた。
で、なんでこんなことになるのかという話。

そもそも、synchronized文が言語レベルでサポートされているのに、わざわざセマフォクラスを作ったのは次のような理由から。

@ 前提とか

  • クリティカルセクションはクリティカルセクションである

待ち行列とは関係ないという話。

@ 愚痴など

  • スレッドがライブラリレベルでのサポートなのに、それの排他処理が言語レベルなんて変という意見

スレッドがライブラリレベルというのは、俺の勝手な思い込みかもしれないけど、スレッドはphobosのstdにいるのでライブラリだろーということ。そしてsynchronizedはD言語の構文。
例えば、自前でスケジューラを組んで、タイマー割り込みでレジスタを直接バチバチ切り替えるようなスレッドを作った場合、クリティカルセクションはどう動くのかという疑問があって、これは、クリティカルセクションを作るだけならプロセッサのtest and setのような命令で排他フラグを操作するとどんなスレッドに対しても可能だけど、「止める」ことや「待たせる」方法に排他フラグをチェックしながらのアイドルループくらいしか選択肢がないという意味で、あまりよくないと思うし、そもそもクリティカルセクションの作成というのは、あるスレッドがセクション内に入った時点で、スケジューラがCPUを別のスレッドに切り替えないようにディスパッチを止めることだと思っているので、スレッドの実装を知らない階層でやることじゃないだろーと思ったため。
実際は、OSにクリティカルセクションを作成するようなAPIがあるのだろうけど。

なんて言いながらも、セマフォクラスでの排他処理にsynchronized文を使っていたり。ただこれは、どうせWindowsスレッドを使っているのでこれでよくて、スレッドの実装を変えるときには、その部分だけ変えればよいという安易な考えによるもの。

@ 本題。

  • 止められた順番にクリティカルセクションに入りたい

前述で、セクションに入った時点でスレッドが切り替わらないようにするといいながら、止められた順番なんて話を持ち出すのは矛盾しているけど、現実では、あるセクションに入るスレッドと入らないスレッドがいて、入らないスレッドまで止める必要はないので(特に時分割の場合)、セクションに入ろうとしたスレッドを入り口で止めたいところ。
で、この止めた順番にセクションに入れてあげるのが、待ち行列という話。
Dのsynchronized文は、止めた順番に入れてあげない実装みたいなので、超高速でクリティカルセクションに入ったり出たりしているスレッドがいると、タイミング的な問題で、クリティカルセクションに全く入れなくなるスレッドがいる。
なので、そうならないように、誰かが先に入っていてクリティカルセクションに入れなかったら、待ち行列FIFOキューのようなもの)にスレッドの識別を入れた後に、スケジューラがCPU時間を割り当てないように設定して、眠って待っていて、クリティカルセクションを出て行く人が、キューをチェックして、中に誰かいたら、(何人かいた場合は先頭の人を)起こして、その人が次にセクションにはいれるようにしてやる方法を取ると、みんな順番に入れるようになるんじゃないかなーと思うので、そうしたいのだけど、なぜかメモリが開放されなくなったりでできない!!!!という最終的には言い訳でした。