マルチスレッドプログラミングは簡単なりや?

有限な資源で無限のInputを捌こうと思ったらどこかでInputを絞る仕組みが無いとスレッドプールなどで工夫を重ねようがどこかで枯渇する気がするのです。(それとは少し違う話だけれど)
16
Akso de la Malbono @Cryolite

ロックが,というよりかは sequential consistency という consistency model 全般にわたる問題だと思う.なので,整合性モデルそのものを見直さない限りは RAII だとか再帰可能なロックだとかであーだこーだ言っても根本的に何も解決しないはず.

2011-10-21 01:40:08
Akso de la Malbono @Cryolite

↓はロック(広く一般には sequential consistency )に composability が欠如している話に言及したもの. composability の欠如は要するにモジュール性の欠如なので,つまりは,まー,ソフトウェア工学的に破綻してると言って良いと思う.

2011-10-21 01:43:07
Akso de la Malbono @Cryolite

sequential consistency が compositional でないことは TAoMP の最初のほうに書いてあるような基本的な話なのでいまさらここで再度言及するまでもなかったですね???

2011-10-21 02:08:31
やまさ @yamasa

見てる: n_sodaさんによるpthreadを使べき場面について http://t.co/uuZVMol1

2011-10-28 00:01:51
やまさ @yamasa

そうですね。pthreadなんか捨ててJavaを使いましょう。

2011-10-28 00:02:30
SODA Noriyuki @n_soda

@yamasa JDK1.5で条件変数やatomic関係のライブラリは入ったし、メモリモデルも十分凶悪なので、Java使ってれば安心かというと全然全くそういうことはないですけどね…(まあCよりはマシだけど)

2011-10-28 00:13:54
やまさ @yamasa

@n_soda マジレス禁止です!!w

2011-10-28 00:14:38
やまさ @yamasa

まあ、スレッドプログラミング特有の難しさってのはあるけど、慣れれば問題ないとは思うけどね。昔からのオイラの持論だけど、ExecutorとBlockingQueueとFutureだけ使ってりゃ大抵のことができるし、十分安全なコードが書ける。

2011-10-28 00:22:40
SODA Noriyuki @n_soda

@yamasa thread poolは、プールが一杯になるとそれ以上、同時実行する処理を足せないという意味で一種の資源なので、資源枯渇問題からは逃げられないような…

2011-10-28 00:29:35
やまさ @yamasa

@n_soda I/O boundな処理は単純なthread poolだと性能が出ませんが、そういうときこそFutureとかBlockingQueueの出番じゃないですかねー

2011-10-28 00:34:33
やまさ @yamasa

@n_soda CPU boundというか、小タスクをガンガン作るようなやつはFork-Joinってパターンがありますし。

2011-10-28 00:35:49
SODA Noriyuki @n_soda

@yamasa 制限なしならいいんですが、remainingCapacity制限つきでBlockingQueueを使うと、制限一杯の状態で、thread poolから呼び出されたスレッドがプールにaddしようとしたらデッドロックしますよね。高負荷時とかだとまだ罠はあるような。

2011-10-28 00:48:49
やまさ @yamasa

@n_soda うーん、確かにそういう落とし穴はありますけど、ある程度慣れてる人ならそういう風にならないように設計するんじゃないですかねえ。上限付きのBlockingQueueって、基本はProducer-ConsumerパターンのProducer側の速度を制限するものですから。

2011-10-28 00:57:00
やまさ @yamasa

@n_soda なので、それ以外のパターンであえて上限付きBlockingQueueを使うことはあまり無いような気がします。

2011-10-28 00:57:59
SODA Noriyuki @n_soda

@yamasa Producer-Consumerパターンで、データの流れが一方向ならいいんですが、いったりきたりするとやばいかなと。自分の属するthread poolに対して処理をaddするケースもでくわしたことが実はあって…(そのケースでは事前に気づいて回避できたんですが…)

2011-10-28 01:03:54
SODA Noriyuki @n_soda

@yamasa その時は、thread poolから呼び出されるスレッドの根本の関数でaddしてたのですぐ気づいたんですが、そこから呼び出されるずっと奥の方の関数でaddしてたりすると気づかない可能性もあるわけで、 http://t.co/nyB8j7WQ の問題は根深いかなと。

2011-10-28 01:08:09
やまさ @yamasa

@n_soda 自身の属するthread poolに処理をaddするのはfork-joinって黄金パターンがあるので、それに上手く載るようにしたいところですね。

2011-10-28 01:11:47
やまさ @yamasa

@n_soda まあ、sequential consistencyが厄介だというのは同意なんですが、大抵の問題はrelease-aquire型のconsistencyで解決可能だと思うんですよね。こちらは合成可能性も持っているので扱いやすいですし。

2011-10-28 01:14:13
SODA Noriyuki @n_soda

@yamasa むむ、それってどういうの? fork-joinの場合、fork中の処理が、さらにfork直後から実行するような処理を後から追加するってのはやらないという感じがしてましたが。(追加するのはfork-joinの外側)

2011-10-28 01:44:23
SODA Noriyuki @n_soda

@yamasa こっちの話はさらに分かりませんでした。勉強したいので、ポインタを示してもらえるとありがたいっす。

2011-10-28 01:46:23
やまさ @yamasa

@n_soda forkは自身のthread poolに子タスクを追加する処理です。threadに空きがあればそこで子タスクは処理されますし、そうでなければタスクはキューに溜まります。

2011-10-28 01:52:37
やまさ @yamasa

@n_soda で、joinでは、子タスクが終了していればその結果を受け取り、そうでなければ現在の継続を覚えておき、現タスクの実行を一旦中止します。そして、キューから別のタスクを取り出してそれを実行します。

2011-10-28 01:55:44
やまさ @yamasa

@n_soda タスクを貯めるところをキューと言いましたが、実際はちょっと違い、forkで投入されたタスクは同じスレッドからはLIFOで取り出されるようになっています。なので、子タスクが別スレッドに横取りされていなければ、切り替わる先はforkしたときの子タスクになるわけです。

2011-10-28 02:00:10
やまさ @yamasa

@n_soda Javaだと ForkJoinPool ってのがその実装になりますね。

2011-10-28 02:01:55
やまさ @yamasa

@n_soda sequential consistencyってのはオブジェクトへの操作がどのスレッドから見ても同じ全順序であることを求めているんですが、これはオブジェクトが複数になったときに矛盾が起こる可能性があります。

2011-10-28 02:09:48