I am using a background thread to generate a series of primitives from a set of vertices.
I have got an existing Node with geometry in it.
this node is attached to render3d.
I would like to swap content the node is referencing to with my new geometry.
I suspect that this isn’t straight forward though…
I mean can I just substutite a node at any time ? even from another thread ? In my head that brings all sorts of problems - what if the node is currently used to be rendered by panda ?
The reparent operation is atomic, so you can reparent your previous node out of the scene graph, then reparent the new node into the scene graph. As long as the new node was already complete at the time you reparented it in, it will not cause problems: either you reparented it in before the render thread found it, in which case it will get rendered this frame; or you reparented it in after the render thread went past that point, in which case it will get rendered next frame.
Note that in this scenario there is a possibility that the render thread will walk past this point of the scene graph right between the time you have switched the first node out and the time you switched the second node in. In this case it won’t render anything at all for this frame. If that’s a problem, you will have to do something to avoid that possibility.
You could, for instance, reverse the operation, so that it swaps in the new node first and then removes the old node, but then you might render two nodes in one frame.
If that’s a problem too, then you have to use some other approach. One idea is to have your thread generate the new primitives and just set it aside somewhere, but not put it directly in the scene graph. Then you can have a task on the main thread that checks to see if the new node is ready, and this task is responsible for actually putting it in the scene graph. Since that operation happens in the main thread, it will always work correctly with respect to the renderer.
Another possibility is to use Mutex locking to protect this critical section of code. Using mutexes is fundamental to multi-threaded programming; if you’re not familiar with the proper use of mutexes, it would probably be worthwhile to read up on them if you’re going to pursue multithreaded development.
Thanks for the answer.
I had a look at the manual but there seems to be nothing about the use of Mutex with the panda threading. In particular the Panda c++ syntax for it.
Is there any Panda reference source somewhere that you know of ?
I understand the principle behind Mutex and Threading.
I’ll try and dig into the source code today and see if I can find out from the code how to use the mutex class with my code.
If I understand the PAnda Mutex class correctly I should use it like this …
//do critical stuff
//do critical other stuff
but this doesn’t seem to work… am I missing something ?
You can’t just create a Mutex on the fly, because each Mutex is then different. When you acquire a mutex, it means that no one else may acquire the same mutex until you release it. So it does you no good to acquire a mutex that no one else has.
You want to create a single Mutex, for instance as a member of your class, that all of your threads can access. Then you can acquire() that mutex to protect your critical stuff.
Mutexes are pretty universal across all threading libraries. They all work the same way, just possibly with minor differences in nomenclature.
You’re creating a mutex in both threads, which doesn’t seem like the way it should be. You’d usually declare the mutex global to both threads, and only acquire/release the lock in your Process().
Note that Panda provides the MutexHolder class to make it easier. It automatically acquires the lock when it is constructed and releases the lock when the MutexHolder goes out of scope.
It would be a good idea to read up about the basics of mutexes before you try using them, as David suggested.
EDIT: Ah, drwr beat me to it.
that makes sense - I thought I had read somewhere in the panda docs that if the name was the same then it would woirk the way as I had coded it. I was assuming that the handling for them was made behind the scenes. I must have miss-read that (or not remember it correctly).
That has cleared things up anyway. Thanks to you both.