Using V8 Part 3
Part 3. Multithreading, extensions and code design
Part 2 is here:
habrahabr.ru/blogs/development/72592')
Part 1 is here:
habrahabr.ru/blogs/development/72474-
MultithreadingMultithreading is implemented in V8 simply: it is not. At all. Only one thread can use V8 at some point in time, and “using” means not necessarily compiling or running javascript, but everything else — creating templates, placing objects on a V8 stack, etc.
Let's try to sweeten this barrel of tar with a couple of spoons of honey.
This architectural solution is not, of course, a consequence of the underdevelopment of programmers from Google. The main purpose of the V8 is a client application - the Chrome browser, which runs a separate process on each individual tab. The same scheme should follow the server application. Our server product uses so-called. "Work" processes that are named pipe join the main process and receive messages for processing. This allows you to fully load multi-core systems and use the actual Windows process manager to switch tasks.
From time to time in the V8 discussion groups there are people who want "real" multi-site. And they are ready to edit the source code of Google long and hard. Usually, the result of these discussions is the following conclusion: it is very difficult and only by Google developers to turn the current V8 code into multi-threaded. You can learn more, for example, here (English and you must be a member of the Google v8-users group):
groups.google.com/group/v8-users/browse_thread/thread/44621a6efef0104fHowever, one thread V8 can dispose of smarter. For the sole “capture” of the V8, you can use the usual critical section of Windows, but it is better to use the tool of the V8 itself: the Locker class. The designer of this class is trying to “capture” the V8 (while awaiting its release), and the destructor “releases” the V8. Thus, code using V8 and working safely in a multi-application will look something like this:
{
v8::Locker locker;
// V8
// ...
}
// V8 ""
* This source code was highlighted with Source Code Highlighter .
The problem is that very often from javascript code we will call our C ++ code. For example, our dblite class from part 2 of this article works with a database. Obviously, during its operation, the V8 is idle in general, for nothing - because our C ++ code most of the time does not interact with the V8, but deals with input / output.
So, the good news is that the V8 provides the Unlocker class, which allows you to “release” the V8 for a while. The Unlocker class in the constructor “releases” the V8, and in the destructor it “captures” again (as opposed to the Locker class). The beauty is that Locker can be invested in each other and Unlocker knows and will work it out correctly, that is, it will release the V8 regardless of the depth of the Locker.
This can be illustrated by correcting our example from part 2 of an article with the dblite class. Let's rewrite the Open function taking into account new knowledge:
Handle<Value> Open( const Arguments& args)
{
if (args.Length() < 1) return Undefined(); // ? !
dblite* db = unwrap_dblite(args.This()); // dblite
string sql = to_string(args[0]); // C++, to_string
bool r;
{
Unlocker unlocker; // V8
r = db->open(sql.data()); // C++
} // unlocker " " V8
return Boolean::New(r);
}
* This source code was highlighted with Source Code Highlighter .
Now, Open () “takes” V8 only for the time it interacts with V8, and all I / O can be done in another thread.
A small lyrical digression. During the exploration of Unlocker features, I came across a bug, as a result of which a simple program using V8 lost 100 MB per second. To its credit, Guglovtsev must be said that the problem was solved very quickly. Currently in the trunk branch, this error has already been fixed and the issue is closed. Details here (English):
code.google.com/p/v8/issues/detail?id=444V8 is able in a primitive way to switch between threads that are trying to capture the sole access to V8 through Locker. There is a call to Locker :: StartPreemption (). Perhaps this solution at some point will be more convenient than others.
-
Extensions and code designCritics of the V8 blame him (besides monotransferability) and in a too “spreading” binding code. Indeed, the designs are a bit cumbersome, and Google provided the matter at the mercy of the programmers themselves. The situation is further aggravated by the need to declare a large number of callback functions of the same type; if you make them ordinary functions in the global scope, then a jumble is also provided.
The simplest solution for V8 classes wrapping C ++ classes might look like this: we declare a special C ++ class - a wrapper. Callback functions make it static methods. The object template must be stored in a single copy, so we also make it static. By analogy with the V8, we start the New function. It might look something like this:
class ScriptDatabase
{
// JavaScript dblite
//
static Handle<Value> Open( const Arguments& args);
static Handle<Value> Execute( const Arguments& args);
static Handle<Value> Select( const Arguments& args);
...
//
static Handle<Value> ErrorCode(Local< String > name, const AccessorInfo& info);
...
// js- obj C++ ScriptDatabase
static dblite* Unwrap(Handle<Object> obj);
//
static Persistent<Object> New( const char * db_name = 0);
// ,
static Handle<Value> Create( const Arguments& args);
};
* This source code was highlighted with Source Code Highlighter .
As for the templates, there is, of course, a lot of room for creativity. And of course there are already some solutions. You can see, for example, the cproxyv8 project:
code.google.com/p/cproxyv8This is how code can come up using cproxyv8:
code.google.com/p/cproxyv8/wiki/UsageThere are other projects that simplify the use of V8. For example, v8-juice:
code.google.com/p/v8-juicev8-juice offers an API for loading the functionality of an arbitrary DLL into javascript (http://code.google.com/p/v8-juice/wiki/Plugins), as well as a convenient way to convert V8 type to C ++ type (http: // code .google.com / p / v8-juice / wiki / ConvertingTypes). And something else.
I must warn you that these are third-party projects and you will use them at your own risk. In my decision, I only managed the code from Google, because I had not yet stumbled upon these extensions when I started. Perhaps now I would use something ...