We don't seem to have much talk on multithreading, so I thought I'd have a think out loud.
I'm wondering on peoples opinion of the following: (even if it's 'well duh!')
One of the bigger issues I've always faced when trying to think in terms of multithreading has been how you share data between processing objects, and deal with potential change in state with that data, and the read/write race conditions that can occur during that change in state.
Now I'm one to often miss the blindingly obvious, so I initially started thinking in terms of reader/writer locks. But this doesn't account for knowing the state of the object (buffering state.. shudder).
Anyway. I'll cut a long story short.
Eventually, I looked at all the code I'd written, and decided it could be broken into 4 parts:
read data, set data,
communicate with other objects, listen for communication.
Now. Having a 'ohh bugger' moment, which became a 'I've wasted so much time' moment, they can be rearranged:
read data,
communicate with other objects,
listen for communication,
set data,
And funnily enough, they can be split down the middle.
read data and send communication to other objects,
read communication and set data
Suddenly I had two operations I could easily have each run in parallel on all my objects.
So, say there are X threads, with Y objects.
on each thread:
process batches of 10 objects,
run 'read data and send communication to other objects'.
sync to other threads
process batches of 10 objects,
run 'read communication and set data'.
I was annoyed with myself because it was simple.
In physics for example, it would boil down to this:
'read data' is find collisions.
'send communication to other objects' is send a message to objects that you are colliding with.
'read communication' is apply physics code to this object (if it didn't send a message) and to those objects who did send a message to this object (recursive).
'set data' is update the position/momentum/etc of the object.
The hardest part is the communication bit, but it's not really that bad. If no collisions are occurring, each object can potentially be being computed on it's own thread - and once collisions start occurring, they all get processed on the same thread, as to avoid races etc. And the best bit is that it's actually not that hard to implement. The locking is very minor as well, with only sending a message really needing a write lock, however it should be possible to get around this most of the time.
If you do the batches in the same order each time, the caching should work fairly well too I guess.
Thoughts?