PxContactModifyCallback and PxScene locking

Hi,

I’m wondering how PxContactModifyCallback is supposed to be used when physx::PxSceneFlag::eREQUIRE_RW_LOCK is enabled in the scene description.

For example, your SnippetContactModification seems to be calling getMass() on a PxRigidDynamic, which is a function that emits a warning if lockRead() has not been used before calling it. However if I try to call lockRead() inside the onContactModify() callback, the result is a deadlock, as I have had to call lockWrite() before fetchResults() on another thread. The same behavior applies to getLinearVelocity() and getAngularVelocity() and others too, I assume. Is calling these functions inside onContactModify() legal, and if it is, how do I work around the locking requirement?

It is legal to call those read operations inside the contact modify callback. You probably could just ignore the warnings about locks (you may be doing this right now, or you have some workaround). However, it is safest to acquire the read locks and it is completely legal to do so inside the callbacks.

However, as you mentioned, there’s a potential deadlock if your application code looks like this:

scene.lockWrite();
scene.simulate(dt);
scene.unlockWrite();

scene.lockWrite();
scene.fetchResults(true);
scene.unlockWrite();

The problem is that the write lock followed by fetchResults is potentially called before the callbacks have been issued. This is a thread race condition. You could fill the … section with work to give PhysX time to complete its work but you have no guarantee that PhysX has completed the simulation until after you’ve acquired your write lock.

The good news is that you have some options to work around this. The simplest would be to introduce the following:

scene.lockWrite();
scene.simulate(dt);
scene.unlockWrite();

scene.checkResults(true);
scene.lockWrite();
scene.fetchResults(true);
scene.unlockWrite();

CheckResults will block until the scene simulation has completed but it doesn’t actually do the additional work that fetchResults does, so it doesn’t require a write lock. This should ensure that you don’t hit deadlocks if you acquire scene locks in your callbacks.

Alternatively, you could pass a completion task to the simulate() method. This task would execute once the entire simulation task chain has completed. You could use this to either call fetchResults() or trigger your main thread to call fetchResults(), whichever works best for you.

Hope this helps

Thanks, that works perfectly. I hadn’t realized checkResults() could be used without acquiring the lock, but it makes sense now.