yoshinoToylogic / bulletsharp

Automatically exported from code.google.com/p/bulletsharp
MIT License
0 stars 0 forks source link

Exception from DynamicsWorld.ContactTest() when running simulations in multiple threads #66

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?
1. Run multiple DynamicsWorld instances at the same time in different threads.
2. Call DynamicsWorld.ContactTest() from multiple threads. Sometimes this will 
result in an exception being thrown.

It's important to only access each DynamicsWorld from a single thread. Doing so 
should avoid threading issues.

What is the expected output? What do you see instead?
I expect each simulation behave as they would in a single-threaded environment, 
which is what happens aside from the frequent exceptions.

Here's the stack trace for the exception I'm getting:
    IndexOutOfRangeException: Index was outside the bounds of the array.
       at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
       at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
       at BulletSharp.ObjectTable.Add(Object obj, Void* unmanagedPointer)
       at BulletSharp.BroadphaseProxy..ctor(btBroadphaseProxy* proxy)
       at BulletSharp.SimpleBroadphaseProxy..ctor(btSimpleBroadphaseProxy* proxy)
       at BulletSharp.BroadphaseProxy.GetManaged(btBroadphaseProxy* broadphaseProxy)
       at BulletSharp.ContactResultCallbackWrapper.needsCollision(ContactResultCallbackWrapper* , btBroadphaseProxy* proxy0)
       at btCollisionWorld.contactTest(btCollisionWorld* , btCollisionObject* , ContactResultCallback* )
       at BulletSharp.CollisionWorld.ContactTest(CollisionObject colObj, ContactResultCallback resultCallback)
       at BulletSharp_Tests.ContactTestCrashTest.PhysicsTest.DoContactTest() in D:\Programming\Custom\BulletSharp Tests\ContactTestCrashTest.cs:line 155
       at BulletSharp_Tests.ContactTestCrashTest.PhysicsTest.MainLoop() in D:\Programming\Custom\BulletSharp Tests\ContactTestCrashTest.cs:line 129
       at BulletSharp_Tests.ContactTestCrashTest.PhysicsTest.Start() in D:\Programming\Custom\BulletSharp Tests\ContactTestCrashTest.cs:line 82
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()

It's unlikely to be a flaw in the Dictionary class so my best guess is that 
either I'm doing something wrong or BulletSharp is using dictionaries in a 
thread-unsafe manner.

What version of the product are you using? On what operating system?
I'm using BulletSharp r626 compiled with Bullet r2709 (Generic build). The same 
issue occurs in the pre-built BulletSharp 2.82 (Generic build).

Please provide any additional information below.
This isn't an isolated occurrence. Occasionally I get the same exception from 
other methods/properties, most often from setting DynamicsWorld.DebugDrawer.

Attached is code that tries to coax the issue into occurring. Hopefully it'll 
fail as spectacularly on your end as well. It's difficult to know when there's 
multithreading involved.

I'd really like to use BulletSharp for a single player / multiplayer game. But 
since the game relies on having both the client and server run in the same 
process it results in the aforementioned issue.

Original issue reported on code.google.com by shiny....@gmail.com on 29 Apr 2014 at 11:46

Attachments:

GoogleCodeExporter commented 8 years ago
I replaced ObjectTable's Dictionary with a ConcurrentDictionary and the problem 
has disappeared. It's a bit of a stopgap solution, though. There may be 
far-reaching effects that I, being unfamiliar with the code, am unaware of. 
Performance may be a little worse as well.

Original comment by shiny....@gmail.com on 2 May 2014 at 1:55

GoogleCodeExporter commented 8 years ago
The reason for using the ObjectTable dictionary is to prevent wrapper objects 
from being recreated every time they are used. That way the garbage collector 
does less work. However, it's worth testing if maybe using the dictionary is 
more of a performance hit than just recreating the objects, especially when 
using the thread-safe collection. There's also the question of when and how the 
objects in the dictionary are destroyed.

ConcurrentDictionary will indeed patch the issue for now. I'll try to think of 
a better solution. Thanks for reporting!

Original comment by andres.traks on 2 May 2014 at 5:36

GoogleCodeExporter commented 8 years ago
BroadphaseProxy objects are no longer stored in the ObjectTable, so this should 
be fixed. More info:
https://github.com/AndresTraks/BulletSharp/pull/11

Original comment by andres.traks on 23 Dec 2014 at 9:29