views:

801

answers:

12

Is it necessary to acquire a lock on a variable before reading it from multiple threads?

+2  A: 

Reading does not require a lock; as long as you don't care about the 'correctness' of the read. It is only dangerous if you attempt to write without a lock.

John Kraft
The original question asked if a lock was required for reading; not locking. Reading does not require a lock, as long as you don't care about the 'correctness' of the read; thus the preface of generally.
John Kraft
You could add that bit about correctness of the read to the answer, and thus remove the generally and the vagueness it carries.
Martinho Fernandes
@Martinho Fernandes - done.
John Kraft
That makes my comment obsolete now, so I removed and upvoted.
Martinho Fernandes
+1  A: 

Necessary? No.

...but if it's possible that another thread could try to write to it during the read (like a collection, etc.) then it might be a good idea.

Justin Niessner
A: 

As long as it doesn't change during others threads execution you don't need to lock it. If change, you should use it.

MaLKaV_eS
+2  A: 

If it is a constant, no.

If it is an updatable value, yes, if you need consistency.

For updatable values where the exact value must be managed, then yes, you should use a lock or other synchronization method for reads and writes; and perhaps block during the entire scope where the value is used.

meklarian
+3  A: 

It depends on whether or not is it a local or shared variable, and whether something else may write to it in the meantime, and what you're going to do after reading it.

If you make a decision based on the variable, consider that the next line of code may then be based on data which is now stale.

Winston Smith
A: 

If the variable is never written to by someone (at least at the time it is accessible), you don't need to lock it, because there are no possibilities for missed updates. The same goes if you don't care about missed updates (meaning it is not a problem if you get an older value). Otherwise you should use some sort of synchronization

Grizzly
Even if you don't care about missing updates, you can get invalid values, if you write only part of an object before a reader steps in...
Martinho Fernandes
A: 

It is 100% necessary unless you are 100% sure that the variable's value won't change while the reader threads are running.

ebpower
+6  A: 

It depends on the type of variable and your platform. For example, reading Int64s is not guaranteed to be atomic on 32 bit machines. Hence, Interlocked.Read.

HTH, Kent

Kent Boogaart
+1 for pointing the "long-issue" (if I had any votes left...)
Martinho Fernandes
votes are back now. +1 for real
Martinho Fernandes
+1  A: 

If the loading of the value is done in 1 assembly instruction, it's not necessary to get a lock. You don't care if the value changed 10 minutes ago or 1 microsecond ago. You just want the value now.

However, if you're loading a HUGE array or picture or something, it'd probably be a good idea to lock it out. In theory, you can get preempted while loading the data and have half of the first item and half of the second item.

If it's a simple variable, though, like a bool or int, it's not necessary.

Jeff Lamb
Beware what you mean by simple variable! `long`s, `double`s and `decimal`s can require more than one instruction to read depending on the underlying architecture.
Martinho Fernandes
Ok. If the variable is smaller than the architecture size, it's one instrution. "bool" and "int" will always fit this bill.
Jeff Lamb
That's correct, I was just making it clear that "simple" variable here does not mean "primitive"-ish type.
Martinho Fernandes
+1  A: 

Answer is it depends. If the value of the variable does not change when the threads are accessing the variable. otherwise, its needed.

Also, You can use Interlocked.XXX series for maintaining atomicity in reading\writing the variable .

aJ
+16  A: 

The short answer is: it depends.

The long answer is:

  • If it is not a shared value, i.e, only one thread can see it (or use it), you don't need any synchronization.

  • If it is an immutable value, i.e., you set it only once and then only ever read, it is safe to do so without synchronization (as long as you don't start reading before the first write completes).

  • If it is a "primitive" type of at most 32-bits (e.g. byte, short, int) you can get stale (old) data when reading. If that doesn't bother you, you're set. If stale data is undesirable, making the variable volatile can fix this problem without additional synchronization for reads. But if you have racing writers, you will need to follow the same advice as for longs below.

  • If it is a "primitive" type longer than 32-bits (e.g. long, decimal, double) you need synchronization, otherwise you could read "half" of one value, "half" of another, and get crazy results. For this the recommended approach is to use the methods in the Interlocked class, for both reads and writes..

  • If it is a reference type, you will need synchronization to avoid seeing an invalid state (Jeff Lamb's picture example is a good one). The lock statement might be enough for that. Again, you need to lock for both reads and writes.

There are some other points to consider (how long to lock, for example), but I think these are enough to answer your question.

Martinho Fernandes
Very thorough. Thanks for your answer!
Andy
+1 this is a great answer.
Winston Smith
+1  A: 

In adition to the answers below you can also do a read lock using the ReadWriterLockSlim.

That would allow you to do only a read lock when reading and a write lock when modifying your variable. Multiple threads can have a read lock at the same time but as soon as a thread requests a write lock all new request are blocked until it is complete.

This sort of locking would be usefull if you are doing alot of reads and not many writes.

As with most multithreading issues, research it enough to understand if it really fits your problem the ReadWriterLock would not be suitable for every locking situation.

Glenn Condron