Is it necessary to acquire a lock on a variable before reading it from multiple threads?
-
3You might get answers to your multi-threading questions by reading [this article](http://www.albahari.com/threading/). There is also a downloadable PDF version on that page. – Marcel Gosselin Nov 03 '09 at 17:11
-
The wide range of responses to this question show there is definitely the need for it. – Jeff Lamb Nov 03 '09 at 17:11
-
5Can you provide a specific example? There are lots of issues around this... Otherwise, "it depends" is the correct answer. – Andy S Nov 03 '09 at 17:12
-
Thanks to all for the comments. @Andy S: No specific case. Just wondered what the proper approach is in various situations. Martinho gave the answer I was after. – André Haupt Nov 04 '09 at 08:42
12 Answers
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 variablevolatile
can fix this problem without additional synchronization for reads. But if you have racing writers, you will need to follow the same advice as forlong
s 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 theInterlocked
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.

- 1
- 1

- 228,013
- 71
- 433
- 510
-
3Can you still get the "half" of one value, "half" of another for longs on apps running in 64bit mode? – Joe Jul 18 '13 at 07:23
-
What @Joe asked. Especially since "pointers" to a reference type would be of 64bit size and could, for example, be checked on null by multiple threads at the same time (check if that 64bit pointer value is 0 internally?), I'd think it wouldn't matter on 64bit platforms, but I'd like to know the actual answer aswell. – Ray May 04 '18 at 13:45
-
1According to the answer (https://stackoverflow.com/a/154803/417939), volatile only works if you have writers who never read, and readers who never write – YantingChen Sep 03 '18 at 09:36
-
@R. Martinho Fernandes `volatile` cannot fix the issue because it creates half fences thus when a *Write* is followed by a *Read* they can be swapped by a CPU. So if the value is not read periodically you have a problem. – Yarl Dec 08 '20 at 15:25
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
.

- 175,602
- 35
- 392
- 393
-
+1 for pointing the "long-issue" (if I had any votes left...) – R. Martinho Fernandes Nov 03 '09 at 17:24
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.

- 228,013
- 71
- 433
- 510

- 5,755
- 4
- 37
- 54
-
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. – R. Martinho Fernandes Nov 03 '09 at 17:20
-
Ok. If the variable is smaller than the architecture size, it's one instrution. "bool" and "int" will always fit this bill. – Jeff Lamb Nov 03 '09 at 17:27
-
That's correct, I was just making it clear that "simple" variable here does not mean "primitive"-ish type. – R. Martinho Fernandes Nov 03 '09 at 17:47
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.

- 1,169
- 7
- 14
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.

- 6,811
- 4
- 37
- 53
-
1The 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 Nov 03 '09 at 17:38
-
You could add that bit about correctness of the read to the answer, and thus remove the generally and the vagueness it carries. – R. Martinho Fernandes Nov 03 '09 at 17:45
-
That makes my comment obsolete now, so I removed and upvoted. – R. Martinho Fernandes Nov 04 '09 at 09:36
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.

- 21,585
- 10
- 60
- 75
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 .

- 34,624
- 22
- 86
- 128
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.

- 6,595
- 1
- 23
- 49
It is 100% necessary unless you are 100% sure that the variable's value won't change while the reader threads are running.

- 8,310
- 3
- 36
- 42
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.

- 242,243
- 40
- 408
- 536
As long as it doesn't change during others threads execution you don't need to lock it. If change, you should use it.

- 1,325
- 3
- 23
- 39
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

- 19,595
- 4
- 60
- 78
-
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... – R. Martinho Fernandes Nov 03 '09 at 17:18