Even though m_value is not volatile, aren't we guaranteed that the set
fuction will commit pending writes upon return?
No - where do you get that idea from?
A combination of things:
1- Static fields are allocated on an app domain basis. Hence, all load
and store IL instructions for the static field will read and write the
same memory location (across threads). 12.3.1 puts this in writing.
Furthermore, a modification of a static field is considered a side effect.
2- 12.6.4 "Conforming implementations of the CLI are free to execute
programs using any technology that guarantees, within a single thread of
execution, that side-effects and exceptions generated by a thread are
visible in the order specified by the CIL."
"An optimizing compiler is free to reorder side-effects and synchronous
exceptions to the extent that this reordering does not change any
observable program behavior."
The set method for the property has a side effect: ie it writes to a
static field. This side effect can be re-orderded with other side
effects in that thread, so long as observed behavior is not altered.
From a practical standpoint, this re-ordering of side effects can only
happen within a method call. The method has no idea what is going to
happen after it returns, so it has no choice but to commit any pending
side effects to the static field via an stsfld IL instruction. The spec
does not state this outright though.
You also argued that the get method could fetch the value from some
cached location rather than the reading the static field. Based on
section, 12.3.2 (method state), I don't think this is possible. If a
method were to cache the value for a static field across calls to the
same method, where would it store the value? For a given method state,
there are three potential places: the evaluation stack, the local
variables array, and the local memory pool.
By definition, the value can't be cached in the evaluation stack,
because it is empty on method entry and must be empty on return of the
method. The local memory pool is also reclaimed on method exit, so its out.
That leaves the local variables array. It is conceivable that an int
could be cached there, but the spec makes no guarantees regarding the
contents of the array upon return and re-entry. Indeed, a simple test
reveals that the contents are in fact *not* preserved.
On entry, the get method has no choice but to use a ldsfld IL
instruction to read the value from memory.
Please elaborate if you disagree.
See http://www.pobox.com/~skeet/csharp/t...latility.shtml
I read your article before I posted my followup, and i believe that it
addresses a different case. Namely, how non-volatile field variables can
be cached on a method's evaluation stack while the method is executing,
and how side effects can be delayed prior to a method's return. This
scenario is different from mine, IMO.
In essense, you are claiming that for the following code:
class Test
{
static int m_value;
static int Value
{
get {return m_value;}
set {m_value = value;}
}
}
that the get method could read and return m_value somehow without using
ldslfd to load the value from memory, and that the side effect in the
set method could be delayed until after the setter returns. I disagree
with both assertions, but I do not think that I have enough evidence to
prove it outright.
Since I can't prove it completely, I think it may make sense to declare
the field as volatile. I do not agree with the article's suggestion of
using lock statements. They seem excessive for values that can be
assigned and read atomically. I understand that they provide
volatileread, volatilewrite semantics, but I can get that without the
overhead of a lock.
Thanks for your insight.
H^2