Click to See Complete Forum and Search --> : [RESOLVED] Threadsafe code, lots of small lock() or fewer big lock()


Grofit
September 21st, 2009, 02:56 AM
Hey,

Im making some existing code thread safe, while trying to keep it high performance. Now im just putting lock(m_TheadLock){...} round all of the shared variable alterations/reads.

There are alot of sections where i could either put locks round each statement, which are things such as doing a collision detection check or adding/removing things from trees. This sounds best to me as this way you would be able to allow any other threads to keep taking actions in the small gaps between each statement, although this would incur more cycles im guessing as you are having to lock alot more frequently, also in some cases i need to create temporary variables to store the result from within the locks which means im allocating a small amount more memory (99% of the time its a simple value type so it shouldnt matter much).

The other route is to lock up entire sections that do alot of actions on volitile objects, so it would be one big lock, which would require me to create fewer temporary variables and make less lock calls, but the active thread would not release the area for other threads until it was complete...

Im currently going to the first method, but if this is the wrong way to go about it i would rather know sooner than later...

Any feedback would be great!

Grofit
September 21st, 2009, 03:11 AM
Oh also on a side note ive just been reading about the ReaderWriterLock class, and it *looks* like this could also be great for me, as there are more areas where im reading from lists/trees etc than writing to them. So im guessing if i use this class rather than a standard lock(someobject){...} i would get better performance...

i would say the read/write ratio is about 80/20...

Arjay
September 21st, 2009, 05:30 PM
I generally prefer to use finer grained locks versus one big uber lock.

In terms of using the ReaderWriterLock class, be sure to check for performance gains using this class as you may not see any gains in all scenarios.

Grofit
September 22nd, 2009, 02:31 AM
Hey,

I havent noticed any massive performance difference currently using the ReaderWriterLock vs common lock(){...} although im sure it just uses monitors underneath the lock pattern.

In all honesty i wouldnt know how to test my system fully to see how much it can handle, its a duplex service to silverlight so unless i make a load of silverlight clients and spam stuff i can only see how it runs with a few clients, and that is fine at the moment.

Ive also swapped over to use ReaderWriterLockSlim, just so i dont get any writer starvation, as i was under the assumption that in the default ReaderWriterLock that a writer gets priority over a reader but apparently it doesnt...

I am using smaller locks at the moment, if performance becomes an issue further down the line then i can try merging certain parts to cut down on some locks and can also try other locking methods... but this works at the moment and by the sounds of it should be the best theoretical performance given the amount of reads vs writes i do...

Arjay
September 22nd, 2009, 09:42 AM
I am using smaller locks at the moment, if performance becomes an issue further down the line then i can try merging certain parts to cut down on some locks and can also try other locking methods... but this works at the moment and by the sounds of it should be the best theoretical performance given the amount of reads vs writes i do...You might be looking at this in the reverse. I believe that using more grannular locks is generally more performant because there is less contention trying to acquire a lock.

Consider the worse case scenario where all your operations are funneled through one lock - most operations would be spending their time waiting to acquire the lock. If you add locks on specific functionality (i.e. use more locks), then lock contention goes down. Performance doesn't usually suffer from the actions of locking and unlocking but rather from the bottlenecks that occur from waiting to acquire locks.

In general, use separate lock objects for operations that can occur in parallel and span the same resource. For example, consider a scenario where you have one lock and two collections. If modifying one collection can be done on a different thread at the same time the other collection is modified, then you probably will see a performance gain if you used two separate locks depending on how frequently the collections are modified and the type of hardware you are running on.

Grofit
September 23rd, 2009, 02:31 AM
Good advice, cheers matey!