First off, you may not need any locks. Reading and writing with an array of a type where the CPU would handle each read and write atomically, is in and of itself thread-safe (but you might want to put in a memory barrier to avoid stale reads).
That said, just like x = 34
for an integer is threadsafe but x++
is not, if you've writes that depend upon the current value (and which are hence a read and a write), then that is not threadsafe.
If you do need locks, but don't want as many as 50, you could stripe. First set up your striped locks (I'll use simple locks rather than ReaderWriterSlim
for smaller example code, the same principle applies):
var lockArray = new object[8];
for(var i =0; i != lockArray.Length; ++i)
lockArray[i] = new object();
Then when you go to use it:
lock(lockArray[idx % 8])
{
//operate on item idx of your array here
}
It's a balance between the simplicity and size of one lock for everything, vs the memory use of one lock for each element.
The big difficulty comes in if an operation on one element depends on that of another, if you need to resize the array, or any other case where you need to have more than one lock. A lot of deadlock situations can be avoided by always acquiring the locks in the same order (so no other thread needing more than one lock will try to get one you already have while holding one you need), but you need to be very careful in these cases.
You also want to make sure that if you are dealing with say, index 3 and index 11, you avoid locking on object 3 twice (I can't think of a way this particular recursive locking would go wrong, but why not just avoid it rather than have to prove it's one of the cases where recursive locking is safe?)