Re: When is "volatile" used instead of "lock" ?
- From: "Peter Ritchie [C#MVP]" <prsoco@xxxxxxxxxxxxxxxxx>
- Date: Sat, 14 Jul 2007 11:08:47 -0400
Okay, so we know .NET 2.0 is violating 335, i.e. it's not CLI-compliant,
with respect to the memory model. Where else is it violating the 335 memory
model? We don't know.
Not big news that .NET 2.0 isn't CLI-compliant, many have argued the 335
memory model (although stricter than most language-specification and
framework memory models) is broken and Vance details how they've tried to
fix it in .NET 2.0. In the general case, maybe it's true that the ECMA
model is broken; from many programmer's points of view: certainly not; they
can still write thread-safe code.
So, where does that leave designers and programmers with respect to
developing something for a .NET platform that we can be certain is
thread-safe? Kinda up that creek without a compliant paddle. We could fall
back to our language specifications and reference material on MSDN and
assume they're all wrong when contradicted by Vance's .NET 2.0 memory model
article. But, the problem is even Vance's article is contradictory to what
the .NET 2.0 JIT is doing. Even then, I'd argue that Vance's article is
anecdotal and has been contradicted by other's of equal stature. Look at
Vance's assertion: "...so all practical memory models have the following
three fundamental rules: 1. The behaviour of the thread when run in
isolation is not changed. Typically, this means that a read or a write from
a given thread to a given location cannot pass a write from the same thread
to the same location. 2. Reads cannot move before entering a lock. 3. Writes
cannot move after exiting a lock." The only time 2 & 3 hold true, even in
..NET 2.0, is in the context of processor write-cache flushing (e.g. the x86
and IA64 memory models; they can't deal with re-sequencing of instructions
because it's outside their control).
Sure, we can say he "meant" something more detailed (like heap memory, not
stack memory); but how do we get that detail out to the development
community? It's impossible.
But, the JIT isn't following the rules that he's detailed unless they only
have to do with processor write-caching.
Also, why should it distinguish between stack and heap memory? Why should
stack memory be disregarded with respect to these rules? What if I were
writing an synchronous method that called an asynchronous method that
accepted a memory reference? If I pass it a reference to stack memory,
there's nothing I can do to tell the compiler that variable should be
treated as volatile by the JIT. For example:
public int Method( )
{
double value1 = 3.1415;
int value2 = 42;
IAsyncResult result = BeginBackgroundOperation(ref value1, ref value2);
// Sit in a loop waiting for up to 250ms at a time
// doing something with the double value...
do
{
value2 = 5;
// doubles aren't atomic, we need to use
// VolatileRead to read the "latest written" value and
// because BeginBackgroundOperation uses
// Thread.VolatileWrite(ref double).
double temp = Thread.VolatileRead(ref value1);
Thread.Sleep(value2);
// ...
} while (!result.AsyncWaitHandle.WaitOne(250, false));
return 1;
}
If the rules only applied to heap memory then that *could* be optimized to
public int Method( )
{
double value1 = 3.1415;
int value2 = 42;
IAsyncResult result = BeginBackgroundOperation(ref value1, ref value2);
do
{
double temp = Thread.VolatileRead(ref value1);
Thread.Sleep(5);
} while (!result.AsyncWaitHandle.WaitOne(250, false));
return 1;
}
I use Thread.Sleep not because it makes sense in this example, only that it
makes the disassembly easier to read for passing a value to a method.
Something like Console.WriteLine would make more sense but that means the
possibility of injecting a some standard output initialization code that
complicates the disassembly.
Good design? Probably not; if I had to review that code I'd likely send it
back for re-write. But if those rules apply to JIT optimization as well as
processor write-caching then the only description of the .NET 2.0 memory
model and the ECMA memory model say it's thread-safe with regard to value1.
"Jon Skeet [C# MVP]" <skeet@xxxxxxxxx> wrote in message
news:MPG.21012ec6eb9cfbc52d9@xxxxxxxxxxxxxxxxxxxxxxx
Peter Ritchie [C#MVP] <prsoco@xxxxxxxxxxxxxxxxx> wrote:<snip>
The violations that you're seeing (well, they're violations of the way<snip>
I read the spec, anyway) - do they occur when reading and writing heap
memory "around" a volatile member, or only when reading and writing
stack value?
.
- Follow-Ups:
- Re: When is "volatile" used instead of "lock" ?
- From: Barry Kelly
- Re: When is "volatile" used instead of "lock" ?
- From: Jon Skeet [C# MVP]
- Re: When is "volatile" used instead of "lock" ?
- References:
- Re: When is "volatile" used instead of "lock" ?
- From: Peter Ritchie [C#MVP]
- Re: When is "volatile" used instead of "lock" ?
- From: Jon Skeet [C# MVP]
- Re: When is "volatile" used instead of "lock" ?
- From: Peter Ritchie [C#MVP]
- Re: When is "volatile" used instead of "lock" ?
- From: Jon Skeet [C# MVP]
- Re: When is "volatile" used instead of "lock" ?
- From: Peter Ritchie [C#MVP]
- Re: When is "volatile" used instead of "lock" ?
- From: Jon Skeet [C# MVP]
- Re: When is "volatile" used instead of "lock" ?
- From: Peter Ritchie [C#MVP]
- Re: When is "volatile" used instead of "lock" ?
- From: Jon Skeet [C# MVP]
- Re: When is "volatile" used instead of "lock" ?
- From: Peter Ritchie [C#MVP]
- Re: When is "volatile" used instead of "lock" ?
- From: Jon Skeet [C# MVP]
- Re: When is "volatile" used instead of "lock" ?
- From: Peter Ritchie [C#MVP]
- Re: When is "volatile" used instead of "lock" ?
- From: Jon Skeet [C# MVP]
- Re: When is "volatile" used instead of "lock" ?
- Prev by Date: Re: a Mod b
- Next by Date: What is Acomplia?
- Previous by thread: Re: When is "volatile" used instead of "lock" ?
- Next by thread: Re: When is "volatile" used instead of "lock" ?
- Index(es):
Relevant Pages
|