はじめに
v8 を利用して、JavaScript 側で定義したコールバックが別スレッドから呼びたかったのでやってみました。具体的には、音声認識エンジン Julius にて、発話待機開始・発話開始・認識終了などのイベントが非同期でやってくるので、それらを JavaScript 側で補足して処理したいと思ったのが発端です。完全に非同期で実行する場合は v8::Isolate を使えば出来そうなコードはちらほらネット上にあったのですが、同一の Context をスレッド間で共有して実行する、という要件を満たすコードが見つからなかったのでまとめてみました。ただ、取り敢えず動きますが、コードを見ていただければ分かる通り、v8 もマルチスレッドプログラミングも良く分からずに書いたので、余りオススメ出来ない内容です(´・ω:;.:...
解説
コード
#include <iostream> #include <thread> #include <mutex> #include <v8.h> std::mutex m; int main(int argc, char const* argv[]) { v8::HandleScope handle_scope; v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); global->Set( v8::String::New("print"), v8::FunctionTemplate::New([](const v8::Arguments& args)->v8::Handle<v8::Value> { v8::String::Utf8Value str(args[0]); std::cout << *str << std::endl; return v8::Undefined(); }) ); v8::Persistent<v8::Context> context = v8::Context::New(NULL, global); v8::Context::Scope scope(context); v8::Handle<v8::String> str = v8::String::New("print('Main thread');"); v8::Handle<v8::Script> script = v8::Script::Compile(str); std::thread t([]{ std::lock_guard<std::mutex> lk(m); { v8::Locker lock; // これをしないと欲しい Context がやってこないので print が undefined と怒られる v8::Context::Scope scope(v8::Context::GetCurrent()); v8::HandleScope handle; v8::Handle<v8::String> str = v8::String::New("print('Sub thread');"); v8::Handle<v8::Script> script = v8::Script::Compile(str); v8::Handle<v8::Value> result = script->Run(); } v8::Context::GetCurrent()->Enter(); // Locker が破棄されると Context->Exit() してるっぽいので実行 }); { std::lock_guard<std::mutex> lk(m); v8::Handle<v8::Value> result = script->Run(); } t.join(); return 0; }
コンパイル
g++ -std=c++0x hoge.cpp -L./v8/ -I./v8/include -lv8 -lpthread
実行
Main thread Sub thread
なんか Exit されちゃったのでもう一回 Enter で入っておきましたよっと…、というかなーーり怪しいコードになっています。