I find myself in a bit of a quandry.
I have a large application which has Google's V8 javascript engine. Some calls are made to the V8 engine on the UI thread. To be nice to the user like everyone recommends, some long operations are run on a separate thread, without hanging the UI thread. However, these long running operations also make calls in to the V8 javascript engine. So multiple threads call in to V8.
Thing is, V8 appears to use thread local storage. This seems to be making my application randomly explode. It's definitely in the class of "How was this possibley working up till now?" bugs.
Without significantly re-architecting my application, I propose an ugly, ugly horrible super-hack: can I make V8 think it's running on a different thread?
In other words, the first time I make a call in to V8, I make a note of the thread. Then, for all other calls to V8, I somehow spoof the thread so the thread local storage/whatever else thread-dependent works.
Can it be done? Will it work? Am I stupid to even consider such a scummy hack?
You should not spoof anything. Instead you should tell V8 that you are trying to use it from the different thread.
In V8 prior to the version 3.2 the only way to do that is to use v8::Locker before using V8 from the different thread. It guarantees both exclusive access to the V8 and initializes internal structures stored in TLS. For more details see http://code.google.com/p/v8/source/browse/branches/3.1/include/v8.h#3189
Starting from the version 3.2 V8 has the concept of isolate. If you are not creating isolates explicitly, V8 implicitly creates the default isolate to keep API compatible. In this case you can still simply use v8::Locker as in older versions. If you are creating isolates explicitly then in addition to acquiring exclusive access with v8::Locker you also have to enter&exit them explicitly in your threads using v8::Isolate::Enter/v8::Isolate::Exit methods or v8::Isolate::Scope. For more details see http://code.google.com/p/v8/source/browse/trunk/include/v8.h#3510
So simple answer that will work in most cases is: use v8::Locker before using V8 from the different thread.
I had the same problem and managed to find the solution partly through this thread. To elaborate on VE's answer, you can not use v8 from multiple threads by default. If you want to, you have to use isolates and locks.
The problem is that you can not go half way, you can't use locks only unless you completely exit and destruct your JS context. Since this is not the case in most non-trivial cases you have to go all the way, and
Create your own v8::Isolate. You can make this global, but (as I understand it) it can not be the default one (because the default one is already in the entered state).
In all your functions that call v8 (and are not guaranteed to be internal) you must enter your isolate (use v8::Isolate::Scope) and
also use 'v8::Locker' objects.
I wrote a small helper object that I use in my public methods and it looks a bit like this:
class SessionLock {
private:
v8::Isolate::Scope scope;
v8::Locker lock;
public:
SessionLock() : scope(getSessionIsolate()), lock(getSessionIsolate()) {}
};
Related
I have a code that looks like this:
myCmd::myCmd(std::string outFile) : _tclInterp(Tcl_CreateInterp()), _outFile(outFile)
{
_myParser = CC::CmdParser(_tclInterp, registerAllCommands);
}
The thread which created the Tcl_CreateInterp() might be different from what is being used in the CC::CmdParser. Internally CC::CmdParser also calls Tcl_DeleteInterp() once all the procedures are complete. It will be a problem if the thread id is different during calls to CreateInterp and DeleteInterp.
How do I associate or tell such that same thread does Tcl_CreateInterp() (in the constructor) and Tcl_DeleteInterp() (in the CmdParser).
NOTE that the CC::CmdParser is a third-party API and I don't have source code.
Tcl interpreter objects internally use thread-specific data extensively in order to avoid most global locks. This goes as far as including thread-specific memory management pools, at least for common allocations, and Tcl code is executed as part of initialising the interpreter state, so it's really not possible to use an interpreter in a different thread from the one in which it was created. The Tcl library checks that you're using it correctly in a few places, at least in some build modes, and will make the process abort() (or Windows's equivalent) if you disobey the rules; that's much friendlier than the crash that would otherwise be coming due to fundamental assumptions not being respected…
This means that you must create, use, and destroy the interpreter on the same thread.
You might be advised to initialise the Tcl interpreter lazily if you can't guarantee that the containing object is used in the same thread that it was created in. You might think that this results in handling of things that isn't really the C++ way, but the thread-bound nature of interpreters means that you've really not got any alternative. (You might want to look at Tcl_CreateExitHandler() for help with cleaning up the interpreter when the thread goes away, but that will only help if Tcl_FinalizeThread() or Tcl_ExitThread() are called; if you're being thread-promiscuous on the C++ side then there's a good chance that you'll be baking in all sorts of problems anyway.)
If the C++ part insists on using multiple threads, you'll have to have a single thread for the Tcl code and use inter-thread messaging to let the other threads tell it things. That's done with Tcl_ThreadQueueEvent(). The canonical way to use that is the thread package, and that includes the canonical example of how to do so (github.com/tcltk/thread/generic/threadCmd.c); most of the complexity in there relates to turning an essentially one-way (but “reliable”) operation into a two-way one that lets you do a procedure call into a different thread; one-way calls are far simpler.
I'm trying to use v8 from c++ inside a thread that isn't the main thread. There's no multi-threading as far as v8 is concerned, all v8 objects are created and destroyed within that thread. Nothing is running in parallel, nothing is being shared. When I run my program from the main thread, everything works fine. When I have the v8 stuff in another thread, I get segmentation fault when I create a v8::HandleScope.
I can't find any useful documentation on how threading is actually addressed with v8. The instruction "use isolates and lockers" pops up often when searching, but I can't find any examples on how this is done. There's this API doc on v8::Isolate, but nothing on that page tells me if I need them in my specific case (I'm not sharing memory or executing in parallel). The docs on v8::Locker() don't even have information about what the class is for. The included samples in the project don't deal with any of this either.
So my questions are...
Do I need to use isolates and/or lockers here?
Could I get a minimal example of how to use them? Even pseudo-code or something would be really useful
You do need V8::Locker in the methods that will be working with the context when calling HandleScope. https://github.com/jasondelponte/go-v8/blob/master/src/v8context.cc#L41 is an example of how I've use the locker with v8. In this example it is used with multiple threads, but I believe the rule applies with single threads also.
Isolates are only needed when you want multiple instances of v8 in parallel.
https://groups.google.com/forum/?fromgroups=#!topic/v8-users/FXpeTYuAqKI Is an old thread I found a bit ago that helped me solve my problem with the library crashing as soon as HandleScope local variable was created.
I'm new with Google's V8 and I'm not sure how to fully use the variable types they give. I'll start by explaining what i wish to flow to be:
In the main thread I want to compile the JS scripts.
In several threads I want to run scripts when I "add" to the context different information using instance->SetAccessor(...) or prototype->Set(...) (or any other option if there is.
I am not sure when I need to do the following:
where and when to create the v8::handleScope? is creating one in the main thread is enough? or I need one for each thread?
where and when to create v8::isolate and v8::locker? should it be per thread or not? should it be before or after the v8::handleScope?
Any info will help (:
If you want to run the scripts in parallel from each thread with no cross-thread sharing, then each thread needs its own isolate. You may or may not actually need one for the main thread, or you could maybe use the default isolate. I'd recommend making sure that the default isolate has been initialized before running any threads though, just in case one of your other threads ends up initializing it. You should be ok if you are using isolates but it won't do any harm to be sure.
If you need cross-thread sharing of objects etc then you'll need to research this and it is likely to be difficult. Not even sure if v8 can really support it yet or not. Having separate isolates and avoiding sharing of objects is much easier.
You should be able to compile your scripts in the context of an isolate intended for the thread that is going to execute it in the main thread and then pass the script and the isolate to the thread and not touch either again in the main thread until the worker thread is done with it. This ought to work, but I've not checked if v8 checks the thread-id that the isolate was created in and the one it executes in. It's worth writing a little test app to check that this will work.
The other option is to check the compilation in the main thread and compile it again in the worker thread and encapsulate the isolate in the thread. This is the way I have done it in the past. It's easier but less efficient.
The handle scope should be allocated on the stack only in the functions where it is needed. Don't use a global variable for the handle scope or allocate it on the heap.
Your compiled script should use a persistent handle.
Enter the handle scope after you have entered the isolate scope.
Few months back, I had come across this interesting scenario asked by a guy (on orkut). Though, I've come up with a "non-portable" solution to this problem (have tested it with small code), but still would like to know what you guys have to say and suggest.
Suppose, I created a DLL, exporting some functionalities, written in C++, for single threaded client. This DLL declares lots of global variables, some maybe const variables (read-only) and others are modifiable.
Anyway, later things changed and now I want the same DLL to work with multi-threaded application (without modifying the DLL); that means, several threads access the functions and global variables from the DLL, and modify them.. and so on. All these may cause global variables to hold inconsistent values.
So the question is,
Can we do something in the client code to prevent multi-access of the DLL, and at the same time, ensuring that each thread runs in it's own context (meaning, when it gets access to the DLL, the DLL's global values are same as it was before)?
Sure, you can always create a wrapper-layer handling multi-threading specific tasks such as locking. You could even do so in a second DLL that links with the original one, and then have the final project link with that new DLL.
Be aware that no matter how you implement it, this won't be an easy task. You have to know exactly which thread is able to modify which value at what time, who is able to read what and when etc. unless you want to run into problems like deadlocks or race conditions.
If you're solution allows it, it's often best to assign a single thread to modify any data, and have all others just read and never write, as concurrent reading access is always easier to implement than concurrent writing access (Boost provides all basic functionality to do so, for example shared_mutex).
Can we do something in the client code to prevent multi-access of the DLL, and at the same time, ensuring that each thread runs in it's own context (meaning, when it gets access to the DLL, the DLL's global values are same as it was before)?
This is the hard part. I think the only way top do this would be to create a wrapper around teh existing DLL. When it is called, it would restore the state (global variables) for the current thread, and save them when the call to the DLL returns. You would need to know all of the state variables in the DLL, and be able to read/write them.
If performance is not an issue, a single lock for the entire DLL would suffice, and be the easiest to implement correctly. That would ensure that only one thread was accessing (reading or writing) the DLL at one time.
I have discovered through trial and error that the MATLAB engine function is not completely thread safe.
Does anyone know the rules?
Discovered through trial and error:
On Windows, the connection to MATLAB is via COM, so the COM Apartment threading rules apply. All calls must occur in the same thread, but multiple connections can occur in multiple threads as long as each connection is isolated.
From the answers below, it seems that this is not the case on UNIX, where calls can be made from multiple threads as long as the calls are made serially.
From the documentation,
MATLAB libraries are not thread-safe.
If you create multithreaded
applications, make sure only one
thread accesses the engine
application.
When I first started using the engine, I didn't run across any documentation on thread safety, so I assumed that it was not thread-safe.
I use a C++ class to synchronize access to an engine instance. For more parallel processing designs, I instantiate multiple instances of the engine class.
(edit) I'm using MATLAB R14 on Solaris. I open the engine using the 'engOpen' call, and close it using 'engClose'. My platform does not crash when the Close is called by a different thread than the one that called Open.
From a user's perspective, Matlab's interpreter is purely single-threaded. To be safe, you probably need to make all access to the engine from a single thread.
Note that internally, Matlab uses plenty of threads. There are GUI threads, and in the last few versions, the interpreter can use multiple threads behind the scenes. But, the interpreter is semantically equivalent to a single-threaded interpreter (with interrupts).
You can use engOpenSingleUse instead of using engOpen to make more than one thread working separately. (Only Windows)