マルチスレッドプログラミングは簡単なりや?
ロックが,というよりかは sequential consistency という consistency model 全般にわたる問題だと思う.なので,整合性モデルそのものを見直さない限りは RAII だとか再帰可能なロックだとかであーだこーだ言っても根本的に何も解決しないはず.
2011-10-21 01:40:08↓はロック(広く一般には sequential consistency )に composability が欠如している話に言及したもの. composability の欠如は要するにモジュール性の欠如なので,つまりは,まー,ソフトウェア工学的に破綻してると言って良いと思う.
2011-10-21 01:43:07sequential consistency が compositional でないことは TAoMP の最初のほうに書いてあるような基本的な話なのでいまさらここで再度言及するまでもなかったですね???
2011-10-21 02:08:31@yamasa JDK1.5で条件変数やatomic関係のライブラリは入ったし、メモリモデルも十分凶悪なので、Java使ってれば安心かというと全然全くそういうことはないですけどね…(まあCよりはマシだけど)
2011-10-28 00:13:54まあ、スレッドプログラミング特有の難しさってのはあるけど、慣れれば問題ないとは思うけどね。昔からのオイラの持論だけど、ExecutorとBlockingQueueとFutureだけ使ってりゃ大抵のことができるし、十分安全なコードが書ける。
2011-10-28 00:22:40@yamasa thread poolは、プールが一杯になるとそれ以上、同時実行する処理を足せないという意味で一種の資源なので、資源枯渇問題からは逃げられないような…
2011-10-28 00:29:35@n_soda I/O boundな処理は単純なthread poolだと性能が出ませんが、そういうときこそFutureとかBlockingQueueの出番じゃないですかねー
2011-10-28 00:34:33@yamasa 制限なしならいいんですが、remainingCapacity制限つきでBlockingQueueを使うと、制限一杯の状態で、thread poolから呼び出されたスレッドがプールにaddしようとしたらデッドロックしますよね。高負荷時とかだとまだ罠はあるような。
2011-10-28 00:48:49@n_soda うーん、確かにそういう落とし穴はありますけど、ある程度慣れてる人ならそういう風にならないように設計するんじゃないですかねえ。上限付きのBlockingQueueって、基本はProducer-ConsumerパターンのProducer側の速度を制限するものですから。
2011-10-28 00:57:00@yamasa Producer-Consumerパターンで、データの流れが一方向ならいいんですが、いったりきたりするとやばいかなと。自分の属するthread poolに対して処理をaddするケースもでくわしたことが実はあって…(そのケースでは事前に気づいて回避できたんですが…)
2011-10-28 01:03:54@yamasa その時は、thread poolから呼び出されるスレッドの根本の関数でaddしてたのですぐ気づいたんですが、そこから呼び出されるずっと奥の方の関数でaddしてたりすると気づかない可能性もあるわけで、 http://t.co/nyB8j7WQ の問題は根深いかなと。
2011-10-28 01:08:09@n_soda 自身の属するthread poolに処理をaddするのはfork-joinって黄金パターンがあるので、それに上手く載るようにしたいところですね。
2011-10-28 01:11:47@n_soda まあ、sequential consistencyが厄介だというのは同意なんですが、大抵の問題はrelease-aquire型のconsistencyで解決可能だと思うんですよね。こちらは合成可能性も持っているので扱いやすいですし。
2011-10-28 01:14:13@yamasa むむ、それってどういうの? fork-joinの場合、fork中の処理が、さらにfork直後から実行するような処理を後から追加するってのはやらないという感じがしてましたが。(追加するのはfork-joinの外側)
2011-10-28 01:44:23@n_soda forkは自身のthread poolに子タスクを追加する処理です。threadに空きがあればそこで子タスクは処理されますし、そうでなければタスクはキューに溜まります。
2011-10-28 01:52:37@n_soda で、joinでは、子タスクが終了していればその結果を受け取り、そうでなければ現在の継続を覚えておき、現タスクの実行を一旦中止します。そして、キューから別のタスクを取り出してそれを実行します。
2011-10-28 01:55:44@n_soda タスクを貯めるところをキューと言いましたが、実際はちょっと違い、forkで投入されたタスクは同じスレッドからはLIFOで取り出されるようになっています。なので、子タスクが別スレッドに横取りされていなければ、切り替わる先はforkしたときの子タスクになるわけです。
2011-10-28 02:00:10@n_soda sequential consistencyってのはオブジェクトへの操作がどのスレッドから見ても同じ全順序であることを求めているんですが、これはオブジェクトが複数になったときに矛盾が起こる可能性があります。
2011-10-28 02:09:48