views:

265

answers:

4

When doing thread synchronization in C# should I also lock an object when I read a value or just changing it?

for example I have Queue<T> object. Should I just lock it when doing the Enqueue and Dequeue or should I also lock it when checking values like Count?

+1  A: 

Depends on what you want to do with lock. Usually this kind of locking needs a reader/writer locking mechanism.

Readers/writers locking means that readers share a lock, so you can have multiple readers reading the collection simultaneously, but to write, you should acquire an exclusive lock.

Mehrdad Afshari
A: 

The CLR guarantees atomic reads for values up to the width of the processor. So if you're running on 32 bit, reading ints will be atomic. If you're running on 64 bit machine, reading longs will be atomic. Ergo, if Count is an Int32 there's no need to lock.

This post is pertinent to your question.

HTH, Kent

Kent Boogaart
Reading an int might be atomic, but computing the count might not necessarily be atomic. It's not just reading an int. It requires a function call, among probably other stuff.
Mehrdad Afshari
And Count is most probably a property, which corresponds to an implicit function call.
Hosam Aly
Computing count? From a property? That would seriously break my expectations for property behavior. The expectation (which is correct in this case) is that accessing the property is simply returning the value of a field.
Kent Boogaart
At least for List<T>, the count is calculated on every access! Maybe Reflector will reveil the details about Queue<T>...
m0rb
+1  A: 

If you don't lock it, you may get an older value. A race condition could occur such that a write operation is performed changing Count, but you would get the value before the change. For example, if the queue has only one item, and a thread calls dequeue, another thread may read the count, find it still 1, and call dequeue again. The second call won't be done until the lock is granted, but at that time the queue would actually be empty.

Hosam Aly
+3  A: 

From MSDN:

A Queue<(Of <(T>)>) can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.

You should ensure no reader is active while an item is queued (a lock is probably a good idea).

Looking at the count in reflector reveals a read from a private field. This can be okay depending on what you do with the value. This means you shouldn't do stuff like this (without proper locking):

if(queue.Count > 0)
    queue.Dequeue();
Cristian Libardo
This would work, however, if you don't share a lock for all reads, you'll end up with poor performance as only one thread can enumerate the collection at the same time.
Mehrdad Afshari