理解v8的Isolate调度

这两天看了一下v8的在多线程情况下多个Isolate的调度原理,别的不多说了还是先看一下测试代码吧

#include <v8.h>
#include <iostream>
#include <pthread.h>
#include <unistd.h>

using namespace v8;

typedef struct _Args
{
		Isolate* isolate;
		char message[256];
} Args;

void* test(void* data)
{
	Args* args = (Args*) data;
	Isolate* isolate = args->isolate;

	if (isolate == NULL)
	{
		std::cout << "null isolate found" << std::endl;
		delete args;
		return NULL;
	}

	Isolate* current = Isolate::GetCurrent();
	if (current == NULL)
	{
		std::cout << "current isolate is null before locker" << std::endl;
	}
	else
	{
		std::cerr << "current isolate is not null before locker" << std::endl;
	}
	Locker locker(isolate);

	current = Isolate::GetCurrent();
	if (current != NULL)
	{
		std::cerr << "current isolate is not null after locker" << std::endl;
	}
	else
	{
		std::cout << "current isolate is null after locker" << std::endl;
	}

	Isolate::Scope isolate_scope(isolate);

	current = Isolate::GetCurrent();
	if (current == NULL)
	{
		std::cerr << "current isolate is null after enter" << std::endl;
	}
	else
	{
		std::cout << "current isolate is not null after enter" << std::endl;
	}

	// Create a stack-allocated handle scope.
	HandleScope handle_scope(isolate);

	// Create a new context.
	Handle<Context> context = Context::New(isolate);

	// Here's how you could create a Persistent handle to the context, if needed.
	Persistent<Context> persistent_context(isolate, context);

	// Enter the created context for compiling and
	// running the hello world script.
	Context::Scope context_scope(context);

	// Create a string containing the JavaScript source code.
	Handle<String> source = String::New(args->message);

	// Compile the source code.
	Handle<Script> script = Script::Compile(source);

	// Run the script to get the result.
	Handle<Value> result = script->Run();

	// The persistent handle needs to be eventually disposed.
	persistent_context.Dispose();

	// Convert the result to an ASCII string and print it.
	String::AsciiValue ascii(result);

	for (int i = 0; i < 3; i++)
	{
		std::cout << *ascii << std::endl;
		sleep(1);
	}

	delete args;
	return NULL;
}

int main(int argc, char* argv[])
{
	pthread_t pids[256];
	int num = 3;
	for (int i = 0; i < num; i++)
	{
		Args* args = new Args();
		args->isolate = Isolate::New();
		int n = sprintf(args->message, "\"first thread\" + %d", i);
		args->message[n] = '\0';
		int ret = pthread_create(&pids[i], NULL, test, args);
		if (ret != 0)
		{
			std::cout << "create pthread" << i << " failed" << std::endl;
			return 1;
		}
	}

	for (int i = 0; i < num; i++)
	{
		pthread_join(pids[i], NULL);
	}

	std::cerr << "first test loop done" << std::endl;

	Isolate* isolate = Isolate::New();
	{
		Locker locker(isolate);
		Isolate::Scope scope(isolate);
	}

	for (int i = 0; i < num; i++)
	{
		pids[i] = 0;
		Args* args = new Args();
		args->isolate = isolate;
		int n = sprintf(args->message, "\"second thread\" + %d", i);
		args->message[n] = '\0';
		int ret = pthread_create(&pids[i], NULL, test, args);
		if (ret != 0)
		{
			std::cout << "create pthread" << i << " failed" << std::endl;
			return 1;
		}
	}

	for (int i = 0; i < num; i++)
	{
		pthread_join(pids[i], NULL);
	}

	std::cerr << "second test loop done" << std::endl;

	Isolate* current = Isolate::GetCurrent();
	for (int i = 0; i < num; i++)
	{
		pids[i] = 0;
		Args* args = new Args();
		args->isolate = current;
		int n = sprintf(args->message, "\"third thread\" + %d", i);
		args->message[n] = '\0';
		int ret = pthread_create(&pids[i], NULL, test, args);
		if (ret != 0)
		{
			std::cout << "create pthread" << i << " failed" << std::endl;
			return 1;
		}
	}

	for (int i = 0; i < num; i++)
	{
		pthread_join(pids[i], NULL);
	}

	std::cerr << "third test loop done" << std::endl;

	return 0;
}

运行结果如下:

current isolate is null before lockercurrent isolate is null before locker
current isolate is null after locker
current isolate is not null after enter
current isolate is null before locker

first thread2
current isolate is null after locker
current isolate is not null after enter
current isolate is null after locker
current isolate is not null after enter
first thread1
first thread0
first thread2
first thread1
first thread0
first thread2
first thread1
first thread0
first test loop donecurrent isolate is null before locker

current isolate is null before lockercurrent isolate is null after locker
current isolate is not null after enter

current isolate is null before locker
second thread0
second thread0
second thread0
current isolate is null after locker
current isolate is not null after enter
second thread1
second thread1
second thread1
current isolate is null after locker
current isolate is not null after enter
second thread2
second thread2
second thread2
second test loop done
current isolate is null before locker
current isolate is null before locker
current isolate is null before locker
current isolate is not null after locker
current isolate is not null after enter
third thread0
third thread0
third thread0
current isolate is not null after enter
current isolate is not null after locker
third thread1
third thread1
third thread1
current isolate is not null after entercurrent isolate is not null after locker

third thread2
third thread2
third thread2
third test loop done

第一组测试是完成多个Isolate对象分别在不同的thread里运行的情况,从结果可以看到,这些Isolate在并行执行,并且当执行了Isolate::Scope之后Isolate::GetCurrent返回值也不空了
第二组测试是完成一个Isolate对象分别在不同的thread里运行的情况,从结果可以看到,这个Isolate实际上是顺序在执行的,同样的,执行了Isolate::Scope之后,Isolate::GetCurrent返回值也不空了
第三组测试是完成DefaultIsolate对象分别在不同的thread里运行的情况,从结果可以看到,DefaultIsoalte实际上也是顺序在执行的,但是与第二组不同的是,Locker执行完成之后Isolate::GetCurrent就已经不空了
其实到了这里,已经很明显了,Locker是用来保证一个Isolate必定同时在一个thread里运行,Isolate::Scope实际上只执行了一句代码Isolate::Enter,它负责将thread local store数据写入,保证后面的执行中依赖于tls的地方都不会出问题,而为什么第三组用DefaultIsolate出现了不同的结果呢
原因其实就在于Locker里对DefaultIsolate做了处理,直接Enter了,看代码

 if (isolate_->IsDefaultIsolate()) {
      // This only enters if not yet entered.
      internal::Isolate::EnterDefaultIsolate();
    }


你可能感兴趣的:(理解v8的Isolate调度)