Comments (5)
- The
volatile
is still necessary because otherwise there would be no fence between the initialization of the object and the assignment to the field otherwise. A new thread could then come along and get the newly published object from the field without a fence and read stale memory all before the initializing thread exited the lock. - Ah! Thanks for letting me know. I'll fix that in the docs. The actual implementation does the right thing.
- You're right, if the is a reference type it would be a good idea to do the standard
if (x == null) throw new ArgumentNullException(...)
. As is, it would likely lead to a different ArgumentNullException in the call to Dictionary.Add(...)
from autolazy.
The volatile is still necessary because otherwise there would be no fence between the initialization of the object and the assignment to the field otherwise. A new thread could then come along and get the newly published object from the field without a fence and read stale memory all before the initializing thread exited the lock.
If there are problems without volatile
, then I don't think volatile
can solve those problems. If I'm wrong, feel free to provide a more detailed sequence of events, ideally with an explanation of why you think it's a problem.
The only problem I can think of is if the field is of a struct type where the struct is larger than the size of a single object reference... but you actually cannot declare such a field as volatile
in the first place, presumably because of the issue I'm worried about. I'm guessing you just don't allow that here, but if you do want to try to support it, I think you'd need to do most of your checks on a synthetic field of a type that isn't susceptible to struct tearing, and only read the payload once you can guarantee it's fully written.
Otherwise, from your description, it sounds like you're concerned about letting a later thread see the results before the initializing thread is finished publishing it to its own consumer (perhaps because the initializing thread has its own state to clean up; in your example, this would be disposing the FileStream and calling Monitor.Exit). I personally don't see a problem with that. Regardless of my opinion, though, if it is a problem, then again it doesn't look like volatile
solves it: this happens whether you have volatile
or not. I think if you want to make sure that nobody gets the initialized object before the initializing thread gets its own, without "punishing" everyone who comes around long after the initialization is done, then you might need an additional synchronization mechanism like a ManualResetEvent
... not sure, didn't think about it too much.
Worst-case without volatile
is that, the later thread happened to read a null
even though the initializing thread thinks it's already written the initialized value, in which case the later thread has to go into the lock to fetch the guaranteed non-null
value. There's a very narrow window where this can happen, and in that narrow window I believe the behavior is correct because Monitor.Enter / Monitor.Exit are both full-fence AFAIK.
from autolazy.
Without the volatile
this optimization is possible:
public static List<string> Settings
{
get
{
// thread-safe double-checked locking pattern generated here
var result = _settings;
if (result == null)
{
lock(_syncRoot) // fence (re-ordering instructions around this comment is not allowed)
{
// however, re-ordering instructions within the lock IS allowed
var result = _settings;
if (result == null)
{
// the compiler / jit / underlying hardware may choose to assign _settings here instead of at the bottom. This is allowed unless _settings is declared volatile.
var settings = new List<string>();
settings.Add("foo");
settings.Add("bar");
_settings = settings; // this must be volatile else it may be moved to the above comment.
}
} // fence (re-ordering instructions around this comment is not allowed)
}
return result;
}
}
from autolazy.
This is Java, however, it is also applicable to c#. I believe the standard windows runtime does not allow write reordering so you can get away with not declaring it volatile, however this guarantee may not hold true in the future or for other runtimes.
from autolazy.
I see... I was thinking just x86/x64, but I guess CPUs in other families might have a memory model that doesn't guarantee that this would be correct without volatile
.
from autolazy.
Related Issues (7)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from autolazy.