前田です。 At Wed, 12 Nov 2003 12:03:28 +0900, Hidetoshi NAGAI <nagai / ai.kyutech.ac.jp> wrote: > From: Tietew <tietew-ml-ruby-dev / tietew.net> > Subject: [ruby-dev:21903] Re: pthread trouble on tcltklib > Date: Wed, 12 Nov 2003 11:20:18 +0900 > Message-ID: <20031112111119.D6F8.TIETEW-ML-RUBY-DEV / tietew.net> > > Windows の例ですが,Ruby が走るネイティブスレッドを一つ決め,そ > > の上で Ruby を走らせています。そのスレッド以外で Ruby に制御は絶 > > 対に渡しません。解決不可能な問題の原因になるので。 > > Windows での実装状況を知らないものでお尋ねします. > tcltklib では Ruby から Tcl/Tk の機能を呼び出すのと同様に > Tcl/Tk から Ruby の機能を呼び出すようになっているのですが, > この Tcl/Tk からの呼び出しが,Tcl/Tk 上の複数スレッドから > 行われた場合にはどのようになるのでしょうか. Windowsではないですけど、mod_rubyではすべてのネイティブスレッドか らのRuby機能の呼び出しを、キューを使ってRuby実行用のネイティブス レッドに転送するようにしてます。 mod_rubyの現在の実装では同時に一つのスレッドの要求しか処理できな いのですが、Ruby実行用のネイティブスレッド内で複数のRubyスレッド を動かせば、原理的には同時に複数の要求を処理できると思います。 肝の部分だけ抜き出すとこんな感じです。 typedef VALUE (*ruby_protect_func_t)(VALUE); typedef struct ruby_request { ruby_interp_func_t func; void *arg; void *result; int state; int done; apr_thread_cond_t *done_cond; struct ruby_request *next; } ruby_request_t; static ruby_request_t *ruby_request_queue = NULL; static void *ruby_thread_start(apr_thread_t *t, void *data) { server_rec *s = (server_rec *) data; ruby_request_t *req; ruby_init_interpreter(s); while (1) { apr_thread_mutex_lock(ruby_request_queue_mutex); while (ruby_request_queue == NULL) apr_thread_cond_wait(ruby_request_queue_cond, ruby_request_queue_mutex); req = ruby_request_queue; if (req->func == SHUTDOWN_RUBY_THREAD) break; req->result = (void *) rb_protect((ruby_protect_func_t) req->func, (VALUE) req->arg, &req->state); ruby_request_queue = ruby_request_queue->next; req->done = 1; apr_thread_cond_signal(req->done_cond); apr_thread_mutex_unlock(ruby_request_queue_mutex); } ruby_finalize_interpreter(); req->done = 1; apr_thread_cond_signal(req->done_cond); apr_thread_mutex_unlock(ruby_request_queue_mutex); return NULL; } apr_status_t ruby_call_interpreter(pool *p, ruby_interp_func_t func, void *arg, void **result, int *state) { apr_status_t status; ruby_request_t *req; req = apr_palloc(p, sizeof(ruby_request_t)); req->func = func; req->arg = arg; req->result = NULL; req->state = 0; req->done = 0; status = apr_thread_cond_create(&req->done_cond, p); if (status != APR_SUCCESS) return status; req->next = NULL; apr_thread_mutex_lock(ruby_request_queue_mutex); if (ruby_request_queue) ruby_request_queue->next = req; else ruby_request_queue = req; apr_thread_cond_signal(ruby_request_queue_cond); while (!req->done) apr_thread_cond_wait(req->done_cond, ruby_request_queue_mutex); apr_thread_mutex_unlock(ruby_request_queue_mutex); if (result) *result = req->result; if (state) *state = req->state; return APR_SUCCESS; } -- 前田 修吾