2012-06-15 3 views
9

Node.js(wxWidgets)用のGUIアドオンを作成していますが、私はマージすることをお勧めしないと思うので、独自のスレッドでGUIループを実行したいそれはNodeのメインスレッドとイベントループを伴います。Node.js C++ Addon:Threading

しかし、新しいスレッドを作成する方法がわかりません。私はそれをuv_queue_work()で走らせました。しかし、GUI専用のスレッドは作成しませんが、ノードのスレッドプールを使用します。これは、作業者がランタイム全体にとどまるため、悪い考えかもしれません。 (これについては不明)

wxWidgets 'wxThreadも使用できます。 libuv git masterに新しい機能uv_thread_createが見つかりました。説明がなく、Node.jsの安定したビルドではまだ利用できないので、それをどのように使用するのか分かりません。

私の質問:マルチスレッドのNode.jsアドオンを作成するための「標準的な」方法とは何ですか?私は他のプロジェクトを見ていましたが、libuvを使って短期間の作業スレッドしか見つけることができませんでした。

+0

私はCを知らない++が、私はプロジェクト 'ノードfibers'がスレッドを作成し、多分(あなたがそれを見逃している場合)が見えることは有用であろうことを認識しています。https:// github.com/laverdet/node-fibers/blob/master/src/fibers.cc – alessioalex

+0

https://github.com/xk/node-threads-a-gogo/を見て、それらの実装方法を見ることもできますそれ。 –

答えて

9

答えは、通常、あなたの仕事をuvイベントキューに送信して、nodejがスレッドの作成と管理を心配するようにして、Nodejsによって管理されるバックグラウンドスレッドを使用することです。

は、node.js v0.10マニュアルに記載されていない定型文例です。

struct Baton 
{ 
    // we need this structure to interact with the uv 
    // the uv_work_t must be the initial element and should store 
    // the callback function to be useful, but the rest 
    // is user defined depending on what is needed to actually do the work. 
    uv_work_t     request; 
    v8::Persistent<v8::Function> callback; 
    // Add more elements to the structure as needed 
    int       countdown; 
}; 


static void AsyncTestWork (uv_work_t* req); 
static void AsyncTestAfter(uv_work_t* req,int status); 
static Handle<Value> AsyncTestPrep(const Arguments& args) 
{ 
    HandleScope scope; 
    if (args.Length() != 1) { 
     ThrowException(Exception::TypeError(String::New("Wrong number of arguments -- needs (callback)"))); 
     return scope.Close(Undefined()); 
    } 

    if (!args[0]->IsFunction()) { 
     ThrowException(Exception::TypeError(String::New("Wrong type of arguments -- needs (callback)"))); 
     return scope.Close(Undefined()); 
    } 

    v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(args[0]); 

    Baton* baton = new Baton(); 
    baton->request.data = baton; 
    baton->callback = v8::Persistent<v8::Function>::New(callback); 
    baton->countdown = 3; 

    uv_queue_work(uv_default_loop(), &baton->request, AsyncTestWork, AsyncTestAfter); 

    return scope.Close(v8::Undefined()); 
} 


static void AsyncTestWork (uv_work_t* req) 
{ 
    // This method will run in a seperate thread where you can do 
    // your blocking background work. 
    // In this function, you cannot under any circumstances access any V8/node js 
    // valiables -- all data and memory needed, MUSt be in the Baton structure 
    Baton* baton = static_cast<Baton*>(req->data); 
    sleep(6); // some fictional work, delaying the return.... 
    baton->countdown -= 1; // my actual work in this 
} 

static void AsyncTestAfter(uv_work_t* req,int status) 
{ 
    // This is what is called after the 'Work' is done, you can now move any data from 
    // Baton to the V8/Nodejs space and invoke call back functions 

    Baton* baton = static_cast<Baton*>(req->data); 

    v8::Handle<v8::Value> argv1[] = { v8::Null(), Number::New(baton->countdown) }; 
    v8::Handle<v8::Value> argv2[] = { v8::Null(), Number::New(23) }; 

    v8::TryCatch try_catch; 
     // Call back to the JS function, you can make as many/few callbacks 
     // as you need, they just go on the event loop queue for now. 
     // Note: that it is mostly customary to call the callback 
     // function just (exactly) which is probably what you want 
     // to do to avoid confusing your users if you make a public api 
     baton->callback->Call(v8::Context::GetCurrent()->Global(), 2, argv1); 
     baton->callback->Call(v8::Context::GetCurrent()->Global(), 2, argv2); 
    if (try_catch.HasCaught()) { 
     node::FatalException(try_catch); 
    } 

    if (baton->countdown > 0) { 
     // resubmit the worker for yet more work 
     uv_queue_work(uv_default_loop(), &baton->request, AsyncTestWork, AsyncTestAfter); 
    } else { 
     // we are finished, clean up and be done 
     baton->callback.Dispose(); 
     delete baton; 
    } 
} 


void init(Handle<Object> exports) 
{ 

    exports->Set(String::NewSymbol("myAsyncTestFunction"), 
       FunctionTemplate::New(AsyncTestPrep)->GetFunction()); 

} 
+2

誰かがこれを素敵な拡張モジュール 'npm install nan'でネイティブnodejs拡張のためにラップしたようです - https://github.com/rvagg/nan – Soren

+0

ありがとうございました!魅力のように動作します。 – webaba