Another little piece of advice to my coworkers…
Here’s a quick tip about using local variables that might reduce your multithreading headaches, at least a little bit.
Developers often think of locally cached variables as useful in one of two ways:
- Small performance optimizations (in cases where the cached value replaces redundant method calls)
- Readability improvements
Well, there’s another way in which local variables are useful (you may already know this; but you may not, which is why I’m mentioning it): avoiding race conditions.
Obviously, not all race conditions. But certain race conditions, particularly those that can potentially result in a nasty
NullReferenceException, can be handily evaded with the assistance of local variables.
Here’s a simple example:
For Each x In GlobalCollection.Items ' Do something with x. Next
Never mind (for now) any other issues you might notice in the above code. I just want to focus on the issue at hand.
Let’s say the above is susceptible to a
NullReferenceException in certain cases, where it may be called before
GlobalCollection is initialized (or after it’s set to
Nothing, for whatever reason).
One attempt to “fix” this error might be to do this:
If GlobalCollection IsNot Nothing Then For Each x In GlobalCollection.Items ' Do something with x. Next End If
Now, the truth is that the above “fix” will probably work about 90% of the time. But it’s really just a ticking time bomb, waiting to blow up at what is almost certainly going to be a very bad time. The reason is that, if
GlobalCollection might be set to
Nothing on a separate thread, this could happen between when the above code checks
If GlobalCollection IsNot Nothing and the following line.
Here’s a superior fix, which is not susceptible to this race condition:
' Here we declare a local variable that is set to whatever object ' GlobalCollection (the field or property) references at this ' moment. Dim localCollection = GlobalCollection ' Now, even if GlobalCollection is set to Nothing, localCollection ' still has a reference to the object it was previously pointing ' to. It's impossible for some external thread to infiltrate this ' local stack frame and change localCollection; therefore once we ' check localCollection IsNot Nothing, we can rule out the ' possibility of a NullReferenceException. If localCollection IsNot Nothing Then For Each x In localCollection.Items ' Do something with x. Next End If