什么是正确使用v8::Locker的方式,并且为什么我必须使用它?

6
我正在尝试使用NDK在Android应用中嵌入v8。
我有一个JNI模块,大致如下(未显示JNI映射代码):
#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();
}

我第一次运行getMagicNumber时,它正确地运行并返回42。当我尝试第二次运行时,它崩溃了。

具体而言,在v8的isolate.h中看到的ASSERT失败:

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

这听起来很像这个问题,建议使用v8::Locker获取“独占访问隔离区”。

getMagicNumber的顶部添加一个简单的Locker l;后,崩溃不再发生。这么容易修复的问题往往会在我不注意时出现问题。

我只有最基本的理解,为什么这样可以解决我的问题,并且我收到编译器警告,说明我正在以过时的方式使用v8::Locker。推荐的方法是向v8::Locker的构造函数提供一个v8::Isolate作为参数,但是我不知道该如何“获取”隔离区。

最终:根据v8的当前状态,正确的解决此问题的方法是什么,以及为什么?

2个回答

7
据我了解,V8隔离是V8运行时的一个实例,具有堆,垃圾收集器和零个或多个V8上下文。 隔离不是线程安全的,并且必须通过v8::Locker进行保护。
通常,要使用V8,您必须首先创建一个隔离。
v8::Isolate* isolate = v8::Isolate::New();

然后,要在任何线程中使用隔离的内容:
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);

此时线程拥有隔离区并可以自由创建上下文、执行脚本等。

为了简化应用程序,V8提供了一个默认的隔离区并放宽了锁定要求,但您只能在始终从同一线程访问V8时使用这些功能。我猜您的应用程序之所以失败是因为第二个调用是从不同的线程进行的。


1
我仍然不完全理解这些代码的每一行都在做什么,但是它对我来说起作用了。谢谢。 - namuol

2
我现在正在学习V8,但我认为你需要调用以下内容:
v8::Locker locker(isolate);
这将创建一个堆栈分配的Locker对象,阻止Isolate在另一个线程上使用。当当前函数返回时,该堆栈对象的析构函数将自动调用,导致Isolate被解锁。
然后你需要调用以下内容:
v8::Isolate::Scope isolateScope(isolate);
这将设置当前线程以运行此Isolate。Isolates只能在一个线程上使用。Locker强制执行此操作,但Isolate本身需要配置为当前线程。这将创建一个堆栈分配的对象,指定与当前线程关联的Isolate。就像Locker一样,当此变量超出范围(当前函数返回时)时,作用域析构函数被调用以取消设置Isolate为默认值。我认为这是必需的,因为许多V8 API调用需要对Isolate的引用,但不会将其作为参数传递。因此,它们需要可以直接访问的Isolate(可能通过每个线程的变量)。
Isolate :: Scope类所做的全部工作就是在构造函数中调用isolate :: Enter(),并在析构函数中调用isolate :: Exit()。因此,如果您想获得更多控制权,可以自己调用Enter()/Exit()。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接