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


發佈了217 篇原創文章 · 獲贊 8 · 訪問量 69萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章