2013-03-24 11 views
5

Próbuję osadzić v8 w aplikacji dla systemu Android przy użyciu NDK.Jaki jest poprawny sposób użycia v8 :: Locker i dlaczego muszę go używać?

Mam moduł JNI, który wygląda mniej więcej tak (JNI kod mapowania nie pokazano):

#include <jni.h> 
#include <android/log.h> 

#include <v8.h> 
using namespace v8; 

static jlong getMagicNumber() { 
    HandleScope handle_scope; 
    Persistent<Context> context = Context::New(); 
    Context::Scope context_scope(context); 

    Handle<String> source = String::New("40 + 2"); 

    Handle<Script> script = Script::Compile(source); 
    Handle<Value> result = script->Run(); 

    context.Dispose(); 

    return result->NumberValue(); 
} 

Pierwszy raz uruchomić getMagicNumber, to działa prawidłowo i zwraca 42. drugi raz próbuję uruchomić to się zawiesza.

Konkretnie, to widać w ASSERT V8 isolate.h zawiedzie:

// Returns the isolate inside which the current thread is running. 
INLINE(static Isolate* Current()) { 
    Isolate* isolate = reinterpret_cast<Isolate*>(
     Thread::GetExistingThreadLocal(isolate_key_)); 
    ASSERT(isolate != NULL); 
    return isolate; 
} 

To brzmi trochę jak this problem, co sugeruje użycie v8::Locker uzyskanie "wyłączny dostęp do izolowania".

Po dodaniu prostego Locker l; do góry getMagicNumber, awaria już nie występuje. Problemy, które same się naprawiają, łatwo się łamią, kiedy nie zwracam na to uwagi.

Mam tylko najsłabsze zrozumienie, dlaczego to rozwiązuje mój problem, i otrzymuję ostrzeżenia kompilatora, że ​​używam v8::Locker w przestarzałym stylu. Zalecaną metodą jest dostarczenie jej z v8::Isolate jako argumentu konstruktora, ale nie mam pojęcia, jak mam "uzyskać" izolat.

Ostatecznie: Jaki jest właściwy sposób rozwiązania tego problemu zgodnie z obecnym stanem v8 i dlaczego?

Odpowiedz

6

Jak rozumiem, izolat V8 jest instancją środowiska wykonawczego V8, wraz z stertą, zbieraczem nieczystości i zerowym lub większym kontekstem V8. Izolatory są chronione przed wątkami i muszą być chronione przez v8::Locker.

Ogólnie używać V8 musi najpierw utworzyć izolat:

v8::Isolate* isolate = v8::Isolate::New(); 

Następnie, aby skorzystać z izolatu z dowolnego wątku:

v8::Locker locker(isolate); 
v8::Isolate::Scope isolateScope(isolate); 

W tym momencie wątek posiada izolacji i można tworzyć konteksty, wykonywać skrypty itp.

Teraz, z korzyścią dla bardzo prostych aplikacji, V8 zapewnia domyślny izolator i rozluźnia wymaganie blokowania, ale mogą używać tych kul, jeśli zawsze uzyskujesz dostęp do V8 z tego samego wątku. Zgaduję, że twoja aplikacja nie powiodła się, ponieważ drugie wywołanie zostało wykonane z innego wątku.

+1

Nadal nie w pełni rozumiem, co każdy z tych wierszy robi, ale to działało dla mnie. Dzięki. – namuol

0

Ja tylko nauka V8 teraz, ale myślę, że trzeba zadzwonić:

v8 :: Locker locker (izolat);

Spowoduje to utworzenie obiektu Locker przydzielonego do stosu, który zablokuje izolat przed użyciem w innym wątku. Kiedy bieżąca funkcja zwraca ten destruktor obiektu stosu zostanie wywołany automatycznie powodując odblokowanie Isolate.

trzeba zadzwonić:

v8 :: :: Zakres isolateScope Isolate (izolat);

Ustawia bieżący wątek, aby uruchomić to izolowanie. Izolatów można używać tylko w jednym wątku. Locker wymusza to, ale samo Isolate musi być skonfigurowane dla bieżącego wątku. Tworzy to obiekt przydzielony do stosu, który określa, który izolat jest powiązany z bieżącym wątkiem. Podobnie jak Locker, gdy ta zmienna wykracza poza zakres (kiedy funkcja zwraca), destruktor Scope zostaje wywołany, aby usunąć ustawienie Isolate jako domyślne. Uważam, że jest to konieczne, ponieważ wiele wywołań interfejsu API V8 wymaga odwołania do izolatu, ale nie należy go traktować jako parametru. Dlatego potrzebują jednego, do którego mogą uzyskać bezpośredni dostęp (prawdopodobnie poprzez zmienne związane z wątkami).

Wszystkie klasy Isolate :: Scope wywołują izolat :: Enter() w konstruktorze i izolują :: Exit() w destruktorze. Dlatego jeśli chcesz mieć większą kontrolę, możesz samemu zadzwonić do Enter()/Exit().