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.
Related
I'm debugging my application, but some module (probably custom) causes deadlock.
Main thread just freezes with some EIP and process hangs, thread info below
thread list
How can I find out what causes this issue? Also, I tried to create dump file and analyze it using windbg and I got that stack:
0077d8ac 7693c9b8 ntdll!NtWaitForMultipleObjects+0xc
0077d8c8 571a2ffd KERNELBASE!WaitForMultipleObjects+0x18
Appreciate any help!
The steps to follow is to first find out if you have any static variables. If yes, then you need to make it thread safe.
Also, if your code is the originator of the multiple threads, check if any data structure is shared with the new thread by any means. Then they also have to be made thread safe.
There may also be some implicit data structures shared... maybe some session... accessing these structures must be streamlined by wrapping these structures in a class and making it threadsafe - and mandating use of the new class over the data structure directly.
What I would try is find the combination of these custom modules that cause the deadlock. Say if you have module A,B,C,D and only enable module A,D and you get the deadlock, then you should take further look into the modules.
Also add debug / log to your custom module in possible time consuming/infinite loop functions.
I'm designing the threading architecture for my game engine, and I have reached a point where I am stumped.
The engine is partially inspired by Grimrock's engine, where they put as much as they could into LuaJIT, with some things, including low level systems, written in C++.
This seemed like a good plan, given that LuaJIT is easy to use, and I can continue to add API functions in C++ and expand it further. Faster iteration is nice, the ability to have a custom IDE attached to the game and edit the code while it runs is an interesting option, and serializing from Lua is also easy.
But I am stumped on how to go about adding threading. I know Lua has coroutines, but that is not true threading; it's basically to keep Lua from stalling as it waits for code that takes too long.
I originally had in mind to have the main thread running in Lua and calling C++ functions which are dispatched to the scheduler, but I can't find enough information on how Lua functions. I do know that when Lua calls a C++ function it runs outside of the state, so theoretically it may be possible.
I also don't know whether, if Lua makes such a call that is not supposed to return anything, it will hang on the function until it's done.
And I'm not sure whether the task scheduler runs in the main thread, or if it is simply all worker threads pulling data from a queue.
Basically meaning that, instead of everything running at once, it waits for the game state update before doing anything.
Does anyone have any ideas, or suggestions for threading?
In general, a single lua_State * is not thread safe. It's written in pure C and meant to go very fast. It's not safe to allow exceptions go through it either. There's no locks in there and no way for it to protect itself.
If you want to run multiple lua scripts simultaneously in separate threads, the most straightforward way is to use luaL_newstate() separately in each thread, initialize each of them, and load and run scripts in each of them. They can talk to the C++ safely as long as your callbacks use locks when necessary. At least, that's how I would try to do it.
There are various things you could do to speed it up, for instance, if you are loading copies of a single script in each of the threads, you could compile it to lua bytecode before you launch any of the threads, then put the buffer into shared memory, and have the scripts load the shared byte code without changing. That's most likely an unnecessary optimization though, depending on your application.
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.
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()) {}
};
This isn't so much of a problem now as I've implemented my own collection but still a little curious on this one.
I've got a singleton which provides access to various common components, it holds instances of these components with thread ID's so each thread should (and does, I checked) have it's own instance of the component such as an Oracle database access library.
When running the system (which is a C++ library being called by a C# application) with multiple incoming requests everything seems to run fine for a while but then it crashes out with an AccessViolation exception. Stepping through the debugger the problem appears to be when one thread finishes and clears out it's session information (held in a std::map object) the session information held in a separate collection instance for the other thread also appears to be cleared out.
Is this something anyone else has encountered or knows about? I've tried having a look around but can't find anything about this kind of problem.
Cheers
Standard C++ containers do not concern themselves with thread safety much. Your code sounds like it is modifying the map instance from two different threads or modifying the map in one thread and reading from it in another. That is obviously wrong. Use some locking primitives to synchronize the access between the threads.
If all you want is a separate object for each thread, you might want to take a look at boost::thread_specific_ptr.
How do you manage giving each thread its own session information? Somewhere under there you have classes managing the lifetimes of these objects, and this is where it appears to be going wrong.