From: "T.Shimomura" Date: 2001-02-21T15:31:42+09:00 Subject: [ruby-list:28130] Re: C からのコールバックでエラー T.Shimomura です。 しばらく前に似たような問題にぶつかって、あちこち調べました。 On Wed, 21 Feb 2001 12:27:05 +0900 "masahiko yamada/Daiwasbcm" wrote: > ここで、‘なぜ必要?’と書いた個所をコメントアウトすると数十件のデー > タを処理した時点で、 > [BUG] rb_gc_mark(); unknown data type 0x0(0x241f570) non object > などと言って落ちてしまいます。コメントをはずしてやると、しばらく順調に > 動いているのですが数千件まで到達するとやはり同じエラーで落ちてしまいま > す。 > Cからのコールバックにブロックを使用する場合に一般的に注意すべき点が > あって私がそれをはずしているのでしょうか? > 教えていただけるとありがたいです。長文失礼しました。 なかださんもおっしゃってますが、Ruby はスレッドセーフではありません。 具体的には、ruby_init() を呼んだスレッドと、その後 Ruby の API を呼ぶ スレッドとが同じでなくてはいけません。 さもないと、スタックの範囲を調べる際にアクセス違反でコケます。 どうしても複数のスレッドから Ruby の API を呼びたければ、一時的に Ruby の GC を無効にするのが手っ取り早いのですが、その時に山田さんが やっているように rb_funcall() で GC を無効にするのはまずいかもしれません。 山田さんの場合、コールバック関数の最後で rb_funcall(rb_mGC, enableID, 0); //なぜ必要? を呼んでますが、これを呼んだ結果、Ruby 内部で GC が有効になってから実際に rb_funcall() を抜けてくるまでの間に、GC が動くようなタイミングがもしあれば 結局は同じことです。発生率は大幅に下がるでしょうが。 コメントをはずしたら問題が出にくくなったのは、これが理由ではないかと。 で、私の場合は、gc.c の gc_enable() と gc_disable() を外部から見えるように して、これを直接呼ぶことでとりあえず逃げました。 この方法はかなりの効果がありました。 もっとも、今でも他のところで落ちることがあるので、スレッド関連の対策は 上記の対応のみで十分かといわれると自信はまったくないのですが。 一番いいのは、(これは、前田修吾さんのアドバイスですが)Ruby を実行する 専用のスレッドを用意して、Ruby に処理させたいことは全部そのスレッドを通 すことですね。私は今これにチャレンジ中です。 -- T.Shimomura redbug@netlife.gr.jp