2013-03-24 7 views
5

Sto cercando di incorporare v8 in un'applicazione Android che utilizza NDK.Qual è il modo corretto di usare v8 :: Locker e perché devo usarlo?

Ho un modulo di JNI che sembra qualcosa di simile (JNI codice di mappatura non mostrato):

#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(); 
} 

La prima volta che corro getMagicNumber, esso viene eseguito correttamente e restituisce 42. La seconda volta che provo a correre esso, si blocca.

In particolare, questo ASSERT visto in v8 di isolate.h fallisce:

// 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; 
} 

Suona un po 'come this problem, che suggerisce di utilizzare v8::Locker per ottenere "accesso esclusivo al isolare".

Aggiungendo un semplice Locker l; all'inizio di getMagicNumber, l'arresto non si verifica più. Problemi che si sistemano e che tendono facilmente a infrangersi quando non presta attenzione.

Ho solo la più tenue comprensione del motivo per cui questo risolve il mio problema, e sto ricevendo avvisi del compilatore che sto usando v8::Locker in modo deprecato. Il metodo consigliato è di fornirgli un v8::Isolate come argomento per il costruttore di v8::Locker, ma non ho idea di come debba "ottenere" un isolato.

In definitiva: qual è il modo corretto per risolvere questo problema in base allo stato attuale di v8 e perché?

risposta

6

Come ho capito, un V8 isolato è un'istanza del runtime V8, completa di un heap, un garbage collector e zero o più contesti V8. Gli isolati sono non thread-safe e devono essere protetti tramite v8::Locker.

In generale, per usare V8 è necessario prima creare un isolato:

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

Quindi, per usare l 'isolato da qualsiasi thread:

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

A questo punto il filo possiede l'isolato e è libero di creare contesti, eseguire script, ecc.

Ora, per il beneficio di applicazioni molto semplici, V8 fornisce un isolamento predefinito e rilassa il requisito di blocco, ma tu è possibile utilizzare queste stampelle solo se si accede sempre a V8 dallo stesso thread. La mia ipotesi è che l'applicazione non è riuscita perché la seconda chiamata è stata effettuata da un thread diverso.

+1

Non riesco ancora a comprendere appieno cosa fanno ciascuna di quelle linee, ma questo ha funzionato per me. Grazie. – namuol

0

sto solo imparando V8 ora, ma penso che è necessario chiamare:

v8 :: Locker Locker (isolare);

Questo creerà un oggetto Locker assegnato che bloccherà l'isolamento da essere utilizzato su un altro thread. Quando la funzione corrente ritorna, il distruttore dell'oggetto stack verrà chiamato automaticamente causando lo sblocco di Isolate.

L'hai bisogno di chiamare:

v8 :: :: Isolare Ambito isolateScope (isolare);

Imposta il thread corrente per eseguire questo isolamento. Gli isolati possono essere usati solo su un filo. L'Locker impone questo, ma l'Isolate stesso deve essere configurato per il thread corrente. Ciò crea un oggetto allocato dallo stack che specifica quale isolamento è associato al thread corrente. Proprio come l'Armadietto, quando questa variabile esce dall'ambito (quando la funzione corrente ritorna) il Distruttore di Scope viene chiamato per annullare l'Isolamento come predefinito. Credo che ciò sia necessario perché molte delle chiamate all'API V8 necessitano di un riferimento a un isolamento, ma non ne prendono uno come parametro. Pertanto hanno bisogno di uno a cui possono accedere direttamente (probabilmente attraverso variabili per thread).

Tutta la classe Isolate :: Scope fa call call :: Enter() nel costruttore e isolate :: Exit() nel distruttore. Quindi se vuoi un maggiore controllo puoi chiamare tu stesso Enter()/Exit().

Problemi correlati