when locking a variable, must i lock it everywhere?
I was wondering if when accessing from multiple threads a variable, must i lock it for every access ? For example, i have a list variable and would like to not be able to access that list while i remove an item from it. Must i lock it even in the threads that just access the data or it is sufficient to lock it in the "remove item" thread. My concern is that if a thread accesses the list stops in the middle of the process , goes to another thread that removes from the list and locks the variable, an error will appear .
Your bathroom door does not have a lock on it. Instead, it has a double-sided sign that says "occupied" on one side, and "unoccupied" on the other. When someone approaches the bathroom, if it is marked occupied, they wait until it is marked unoccupied. If it is marked unoccupied, they set the sign to occupied and go in. When they leave, they set the sign back to unoccupied.
(Some negotiation mechanism also must exist to handle the situation where there are two or more people waiting - who gets in first? And also, what happens when two people approach an unoccupied bathroom at the same time -- who wins? But we'll ignore those wrinkles; they are not germane to the analogy.)
This scheme works just fine. Your question is "if someone ignores the sign, or forgets to change it, can I ever be in a situation where there are two people in the bathroom at the same time?"
Yes, obviously you can. If you don't believe me, then I encourage you to try it with your bathroom some time and see what happens when someone ignores the protocol. A resource access protocol only protects access to that resource if everyone honours the protocol!
If you wish to keep a collection in a consistent state (or any other object you are protecting with a lock), you must lock on reads and writes.
There are some 'exceptions', like using a ReaderWriterSlimLock, you still need to acquire a lock for writes but you can perform multi-threaded reads efficiently:
Use ReaderWriterLockSlim to protect a resource that is read by multiple threads and written to by one thread at a time. ReaderWriterLockSlim allows multiple threads to be in read mode, allows one thread to be in write mode with exclusive ownership of the lock, and allows one thread that has read access to be in upgradeable read mode, from which the thread can upgrade to write mode without having to relinquish its read access to the resource.
I've asked myself that question several times and come to the realization that the moment this question comes up, the synchronization protocol is most likely broken. In a sound synchronization discipline, the desire to do an unprotected access doesn't even come up.
The only exception I can think of is that you have some sort of counter, protected by the lock, and you just want to check it for statistical/informational purposes. If that's all you're interested in AND you know that reads/writes to that counter variable are atomic on your particular platform and memory model (and every future platform that this particular software is even remotely possible to run on), then feel free to access the counter without a lock. The second precondition is difficult to meet anyway, so you should not do it.
Using lock on an object doesn't really lock the object. The lock object is really just a token, so you can lock on any object as long as all threads agree on the same locking object for both reading and writing of the shared state in question. The convention is to use a private readonly instance of Object and lock on that.