volatile keyword causes error when compiling

  • Thread starter Thread starter Jim H
  • Start date Start date
J

Jim H

I have the following line in my cs file:
private volatile bool m_bShuttingDown = false;

I get the following error trying to compile:
error CS0518: The predefined type
'System.Runtime.CompilerServices.IsVolatile' is not defined or imported

ComilerServices is in the AssemblyInfo.cs. Is there somewhere else I need
to import this? It does not appear as an option if I try to add a
reference. 'System.Runtime.CompilerServices is in the AssemblyInfo.cs by
default.

Thanks,
jim
 
I don't believe "volatile" is supported in Compact Framework projects (I
might be wrong on this one though)
A workaround would be using
lock(bShuttingDown)
{
// do something with bShuttingDown here
}
 
Thanks again for all the replies (to this and other questions).

I'm not worried about the lock. I'm using volatile because that variable is
only changed from outside a thread that is looping and checking that
variable. I don't want the compiler to optimize it out because that code
executed in that thread never changes the value of that variable. In C/C++
I'd use volatile to prevent this. What would I use here? It's not a
resource I have to worry about locking.

jim
 
Jim H said:
Thanks again for all the replies (to this and other questions).

I'm not worried about the lock. I'm using volatile because that variable is
only changed from outside a thread that is looping and checking that
variable. I don't want the compiler to optimize it out because that code
executed in that thread never changes the value of that variable. In C/C++
I'd use volatile to prevent this. What would I use here? It's not a
resource I have to worry about locking.

You should still use lock, for the same reason you'd use volatile in
C/C++. Basically, entering a lock performs a volatile read, and exiting
a lock performs a volatile write. That way when you've written a new
value, it definitely gets "flushed" to main memory, and when you try to
read a value, it definitely comes *from* main memory.
 
Ok, thanks.
jim

Jon Skeet said:
You should still use lock, for the same reason you'd use volatile in
C/C++. Basically, entering a lock performs a volatile read, and exiting
a lock performs a volatile write. That way when you've written a new
value, it definitely gets "flushed" to main memory, and when you try to
read a value, it definitely comes *from* main memory.
 
Jim,

You are correct that "volatile" is missing from .NETCF and also that
locking the item is over-kill. For a simple boolean value, there is no need
for either a lock or a volatile keyword on CF.

There are two compilers at issue here that one might have to worry about --
the C# compiler in Visual Studio that produces the managed IL binary and
the CF Just-In-Time compiler that produces the native code on the device.
In my experience, I have never seen the C# compiler optimize out a
reference like the one you describe and I don't think it ever will (that is
just a guess however, I don't work on the C# team). I can, however,
guarantee that the CF JIT compiler will never optimize the accesses to a
field in such a way that would require a "volatile" keyword. All fields are
treated as volatile in CF. You can assume that any simple assignment to a
field will occur immediately and that any read of a field will always
re-read the value from memory. However, anything more complex than simple
assignment or reading WOULD require the use of locking or perhaps the
methods of theSystem.Threading.Interlocked class.

All that being said, .NET CF v2 will have support for the "volatile"
keyword and I would recommend using it when it becomes available. Although
it will have no immediate effect on your code, it will protect against any
future changes to the C# or JIT compilers in the distant future.

Brian

--------------------
From: "Jim H" <[email protected]>
Newsgroups: microsoft.public.dotnet.framework.compactframework
References: <[email protected]>
Subject: Re: volatile keyword causes error when compiling

Thanks again for all the replies (to this and other questions).

I'm not worried about the lock. I'm using volatile because that variable is
only changed from outside a thread that is looping and checking that
variable. I don't want the compiler to optimize it out because that code
executed in that thread never changes the value of that variable. In C/C++
I'd use volatile to prevent this. What would I use here? It's not a
resource I have to worry about locking.

jim

This posting is provided "AS IS" with no warranties, and confers no rights.
 
Thanks for the info Brian. I appreciate it.
Jim

Brian Smith said:
Jim,

You are correct that "volatile" is missing from .NETCF and also that
locking the item is over-kill. For a simple boolean value, there is no
need
for either a lock or a volatile keyword on CF.

There are two compilers at issue here that one might have to worry
about --
the C# compiler in Visual Studio that produces the managed IL binary and
the CF Just-In-Time compiler that produces the native code on the device.
In my experience, I have never seen the C# compiler optimize out a
reference like the one you describe and I don't think it ever will (that
is
just a guess however, I don't work on the C# team). I can, however,
guarantee that the CF JIT compiler will never optimize the accesses to a
field in such a way that would require a "volatile" keyword. All fields
are
treated as volatile in CF. You can assume that any simple assignment to a
field will occur immediately and that any read of a field will always
re-read the value from memory. However, anything more complex than simple
assignment or reading WOULD require the use of locking or perhaps the
methods of theSystem.Threading.Interlocked class.

All that being said, .NET CF v2 will have support for the "volatile"
keyword and I would recommend using it when it becomes available. Although
it will have no immediate effect on your code, it will protect against any
future changes to the C# or JIT compilers in the distant future.

Brian

--------------------


This posting is provided "AS IS" with no warranties, and confers no
rights.
 
Brian Smith said:
You are correct that "volatile" is missing from .NETCF and also that
locking the item is over-kill. For a simple boolean value, there is no need
for either a lock or a volatile keyword on CF.

There are two compilers at issue here that one might have to worry about --
the C# compiler in Visual Studio that produces the managed IL binary and
the CF Just-In-Time compiler that produces the native code on the device.
In my experience, I have never seen the C# compiler optimize out a
reference like the one you describe and I don't think it ever will (that is
just a guess however, I don't work on the C# team). I can, however,
guarantee that the CF JIT compiler will never optimize the accesses to a
field in such a way that would require a "volatile" keyword. All fields are
treated as volatile in CF.

You can assume that any simple assignment to a
field will occur immediately and that any read of a field will always
re-read the value from memory. However, anything more complex than simple
assignment or reading WOULD require the use of locking or perhaps the
methods of theSystem.Threading.Interlocked class.

All that being said, .NET CF v2 will have support for the "volatile"
keyword and I would recommend using it when it becomes available. Although
it will have no immediate effect on your code, it will protect against any
future changes to the C# or JIT compilers in the distant future.

That to me suggests that you should be using lock now. There's no way
of guaranteeing that your code won't later be running on a JIT which
*doesn't* optimise accesses to the field in a suitably nasty way.

I for one don't want to have to rewrite all my existing code later in
order to have a clear conscience about thread safety.
 
While lock can be very useful, it does nothing to help this particular
situation. There is no thread safety issue here -- the CLR specification
guarantees that writes and reads to properly aligned variables of 32-bits
or less will always be atomic. From what we have been told about this
scenario, it involves only one write and read to a small field. If more
than one field was getting modified or read and those operations needed to
take place atomically or in a particular order, then lock would be the
correct solution.

What Jim is concerned about is that a compiler might eliminate the read
entirely, not that it might take place out of order. The presence or
absence of a "lock" statement around the use of an object will not change
the code generation of either the C# or JIT compilers beyond adding a call
out to a Monitor method. The actual field access would be unchanged.

Without the use of the "volatile" keyword, a compiler is technically
allowed to re-order memory accesses or delay them but it doesn't give
permission to eliminate the access completely unless the compiler can
really know that there is no other thread that has access to the object in
question and could modify it "behind its back." I promise you that the .NET
CF JIT compiler will never optimize out a field access to a globally
visible object and for the forseeable future it will not even delay or
otherwise complicate field accesses.

Of course, after all that "promising" and "guaranteeing" you should look at
the disclaimer I am told to put at the end of every post :-)

Brian

--------------------
From: Jon Skeet [C# MVP] <[email protected]>
Subject: Re: volatile keyword causes error when compiling
Date: Fri, 24 Sep 2004 09:26:40 +0100

Brian Smith said:
You are correct that "volatile" is missing from .NETCF and also that
locking the item is over-kill. For a simple boolean value, there is no need
for either a lock or a volatile keyword on CF.

There are two compilers at issue here that one might have to worry about --
the C# compiler in Visual Studio that produces the managed IL binary and
the CF Just-In-Time compiler that produces the native code on the device.
In my experience, I have never seen the C# compiler optimize out a
reference like the one you describe and I don't think it ever will (that is
just a guess however, I don't work on the C# team). I can, however,
guarantee that the CF JIT compiler will never optimize the accesses to a
field in such a way that would require a "volatile" keyword. All fields are
treated as volatile in CF.

You can assume that any simple assignment to a
field will occur immediately and that any read of a field will always
re-read the value from memory. However, anything more complex than simple
assignment or reading WOULD require the use of locking or perhaps the
methods of theSystem.Threading.Interlocked class.

All that being said, .NET CF v2 will have support for the "volatile"
keyword and I would recommend using it when it becomes available. Although
it will have no immediate effect on your code, it will protect against any
future changes to the C# or JIT compilers in the distant future.

That to me suggests that you should be using lock now. There's no way
of guaranteeing that your code won't later be running on a JIT which
*doesn't* optimise accesses to the field in a suitably nasty way.

I for one don't want to have to rewrite all my existing code later in
order to have a clear conscience about thread safety.

This posting is provided "AS IS" with no warranties, and confers no rights.
 
Brian Smith said:
While lock can be very useful, it does nothing to help this particular
situation.

There should be. Acquiring a lock involves a volatile read, and
releasing a lock involves a volatile write.
There is no thread safety issue here -- the CLR specification
guarantees that writes and reads to properly aligned variables of 32-bits
or less will always be atomic.

Atomicity is almost irrelevant here - stale data is the concern. They
are two very separate issues.
From what we have been told about this
scenario, it involves only one write and read to a small field. If more
than one field was getting modified or read and those operations needed to
take place atomically or in a particular order, then lock would be the
correct solution.

What Jim is concerned about is that a compiler might eliminate the read
entirely, not that it might take place out of order. The presence or
absence of a "lock" statement around the use of an object will not change
the code generation of either the C# or JIT compilers beyond adding a call
out to a Monitor method. The actual field access would be unchanged.

The field access could not be reordered to outside the lock statement,
due to the volatile read/write semantics of locks.

See http://www.pobox.com/~skeet/csharp/threads/volatility.shtml for my
understanding of the topic.
Without the use of the "volatile" keyword, a compiler is technically
allowed to re-order memory accesses or delay them but it doesn't give
permission to eliminate the access completely unless the compiler can
really know that there is no other thread that has access to the object in
question and could modify it "behind its back." I promise you that the .NET
CF JIT compiler will never optimize out a field access to a globally
visible object and for the forseeable future it will not even delay or
otherwise complicate field accesses.

Of course, after all that "promising" and "guaranteeing" you should
look at the disclaimer I am told to put at the end of every post :-)

Indeed. I think I'll stick to writing code which is guaranteed to be
thread-safe by the spec, which I assume the CF will still obey. If
nothing else, it means I can use the same coding models for the CF and
the desktop, which makes life simpler. If acquiring a lock turns out to
be a bottleneck in the code, I'll reconsider at that point with heavy
comments. It hasn't been in the past though.

(Most classes don't need to be thread-safe, of course, so this only
affects "boundary" classes.)
 
Jon,
Your understanding of "lock" is a bit wrong. As I stated before, lock does
not have any effect on JIT compiler code generation beyond adding callouts
to Monitor.Enter and Exit. I have double-checked today with the desktop CLR
team and this is equally true on both runtimes. Those callouts make sure
that any hardware memory cache is flushed (important on multi-proc
machines) but doesn't change code generation.

So if you have a code snippet like:

while (!m_bShuttingDown) {
... do some stuff...
}

and m_bShuttingDown is not declared as volatile, the JIT compiler is free
to optimize the check in such a way that m_bShuttingDown is not reloaded
each time through the loop. This is true even if you have a "lock" around
the check.

So what is a developer to do about a situation like this since "volatile"
is missing from .NET CF v1?

- if you are building your app using .NET CF v1 tools (Visual Studio 2003)
and targeting only CF devices, don't worry about it. .NET CF currently
treats everything as volatile. Compatibility is very important to us, so if
some future version of .NET CF changed this default policy, you can be sure
we wouldn't break v1 apps. Presumably that would involve disabling those
future optimizations for code built with the v1 tools.

- if you are building your app using v1 tools and want to target both
devices and the desktop runtime, then I would use the
System.Threading.Interlocked class to access my data.

- if you are building your app using .NET CF v2 tools (Visual Studio 2005
"Whidbey") then use "volatile". That will ensure smooth operation across
all platforms today and in the future with the highest level of performance.

Brian

--------------------
From: Jon Skeet [C# MVP] <[email protected]>
Subject: Re: volatile keyword causes error when compiling
Date: Sat, 25 Sep 2004 07:27:05 +0100

Brian Smith said:
While lock can be very useful, it does nothing to help this particular
situation.

There should be. Acquiring a lock involves a volatile read, and
releasing a lock involves a volatile write.
There is no thread safety issue here -- the CLR specification
guarantees that writes and reads to properly aligned variables of 32-bits
or less will always be atomic.

Atomicity is almost irrelevant here - stale data is the concern. They
are two very separate issues.
From what we have been told about this
scenario, it involves only one write and read to a small field. If more
than one field was getting modified or read and those operations needed to
take place atomically or in a particular order, then lock would be the
correct solution.

What Jim is concerned about is that a compiler might eliminate the read
entirely, not that it might take place out of order. The presence or
absence of a "lock" statement around the use of an object will not change
the code generation of either the C# or JIT compilers beyond adding a call
out to a Monitor method. The actual field access would be unchanged.

The field access could not be reordered to outside the lock statement,
due to the volatile read/write semantics of locks.

See http://www.pobox.com/~skeet/csharp/threads/volatility.shtml for my
understanding of the topic.
Without the use of the "volatile" keyword, a compiler is technically
allowed to re-order memory accesses or delay them but it doesn't give
permission to eliminate the access completely unless the compiler can
really know that there is no other thread that has access to the object in
question and could modify it "behind its back." I promise you that the .NET
CF JIT compiler will never optimize out a field access to a globally
visible object and for the forseeable future it will not even delay or
otherwise complicate field accesses.

Of course, after all that "promising" and "guaranteeing" you should
look at the disclaimer I am told to put at the end of every post :-)

Indeed. I think I'll stick to writing code which is guaranteed to be
thread-safe by the spec, which I assume the CF will still obey. If
nothing else, it means I can use the same coding models for the CF and
the desktop, which makes life simpler. If acquiring a lock turns out to
be a bottleneck in the code, I'll reconsider at that point with heavy
comments. It hasn't been in the past though.

(Most classes don't need to be thread-safe, of course, so this only
affects "boundary" classes.)

This posting is provided "AS IS" with no warranties, and confers no rights.
 
Brian Smith said:
Your understanding of "lock" is a bit wrong. As I stated before, lock does
not have any effect on JIT compiler code generation beyond adding callouts
to Monitor.Enter and Exit.

Calls to Monitor.Enter and Monitor.Exit act as volatile reads and
writes though respectively, which affects what the JIT can treat as
"cachable".
I have double-checked today with the desktop CLR
team and this is equally true on both runtimes.

Did they actually say that Monitor.Exit and Monitor.Enter don't act as
volatile reads and writes? If so, I submit that the JIT breaks the CLI
spec.
Those callouts make sure
that any hardware memory cache is flushed (important on multi-proc
machines) but doesn't change code generation.

That should include not using any values in registers which were read
prior to the call to Monitor.Enter - that's effectively a cache too.
So if you have a code snippet like:

while (!m_bShuttingDown) {
... do some stuff...
}

and m_bShuttingDown is not declared as volatile, the JIT compiler is free
to optimize the check in such a way that m_bShuttingDown is not reloaded
each time through the loop. This is true even if you have a "lock" around
the check.

I still dispute that. If you have a lock around the check and a lock
around any change to the variable, the read of m_bShuttingDown must
*logically* come after the call to Monitor.Enter in the thread's memory
ordering, and the write must logically come before the call to
Monitor.Exit in the writing thread's memory order. This is according to
section 12.6.7 of the CLI spec partition 1.

If that *isn't* the case, pretty much every multi-threaded program
almost anyone is writing today isn't thread-safe by the spec.

Fortunately, it's not just my reading of the spec which says this -
Vance Morrison confirmed it for me when I was first interested in this
area. Chris Brumme's blog explains it in a similar way:
http://blogs.msdn.com/cbrumme/archive/2003/05/17/51445.aspx

I'm surprised that the CLR team are disputing this. Could you put to
them the piece of code:

public class StopFlag
{
object stateLock = new object();

bool stopping;
public bool Stopping
{
get
{
lock (stateLock)
{
return stopping;
}
}
set
{
lock (stateLock)
{
stopping = value;
}
}
}
}

and then in two client classes:

while (!stopFlag.Stopping)
{
....
}

and

stopFlag.Stopping = true;

I believe this is thread-safe. Do they definitely contend that it
isn't?
 
Jon,

You have opened up quite a can of worms here, and one that is a bit off
topic from the original question and the Compact Framework. So before I go
deeper into the desktop CLR behavior (coming in the next paragraph) let me
just say to Jim and those who may be more interested in the practical CF
questions raised by the original post: all my statements about CF v1 and v2
behavior and suggestions still hold true. Jim, your original code is fine
for CF without any volatile, locks, etc. If you need your code to run
unmodified on both CF v1 and the desktop CLR, the simplest and best
performing way would be to use the System.Threading.Interlocked class. The
point that gets clarified below is that using "lock" can also be used to
achieve this goal, though at a higher cost.

Now on to a discussion of the desktop CLR and some theoretical issues,
courtesy of Vance Morrison. Vance was my source for my earlier comments
about desktop CLR behavior. I passed your last message on to him for
further comment.

The remainder of this message is actually Vance speaking:

First, I would like to apologize for not being precise when I was
corresponding with Brian. If there is one thing that memory models have
taught me, is that you can’t have a worthwhile conversation unless you are
being very precise. I now realize that I really did not understand the
question I was being asked and I was misleading in my answer. Sorry about
that.

Second I would like to thank Jon for getting precise and given a real live
coding example that we can talk about, which I will repeat here for
clarity.

public class StopFlag
{
object stateLock = new object();

bool stopping;
public bool Stopping
{
get
{
lock (stateLock)
{
return stopping;
}
}
set
{
lock (stateLock)
{
stopping = value;
}
}
}
}

and then in two client classes:

while (!stopFlag.Stopping)
{
...
}

and

stopFlag.Stopping = true;


The question before us is does this code work? In particular could the
JIT optimize the while loop into an infinite loop because on that thread
there are not modifications to the initial value of ‘false’. In
particular do the volatile accesses caused by the ‘lock’ statement force
the compiler not to perform this optimization?

The answer is YES the code above will work. All reads that happened after
a lock is entered must stay after the lock. Thus in the code above it
would be illegal to hoist the read of the `stopping’ variable in the while
loop back to the initialization to false (Which is what the JIT would be
doing if it optimized the while loop to be infinite).

If you think about it, this restriction HAS to be true for ‘lock’ to
achieve its goals as a multi-threaded synchronization construct. The idea
is that you take a lock, at which point you have exclusive access to some
portion of memory (which is NOT necessarily marked volatile), and then you
release the lock. If reads were hoisted before the lock you would not have
this exclusive access (you would be seeing memory in a state before the
lock was taken, which means other threads could be modifying it).

Now what I told Brian, that in the present JIT the ‘lock’ instructions don’
t change code generation also happens to be true. This is more an
artifact of how we implemented the JIT, however. As with most compilers,
the JIT assumes that ANY call (including the call to lock helpers), might
modify any ‘reachable’ memory (the JIT still considers its own local
variables specially). This effectively ‘kills’ any hoisting across calls
(since the JIT assumes that the call might have changed ANY reachable
memory). This rule subsumes the rule we need for locks, and so we get
the right semantics for the ‘lock’ helpers for free.

Sorry about any confusion I caused. I hope my explanation above clarifies
things.

Vance

This posting is provided "AS IS" with no warranties, and confers no rights.
 
Brian Smith said:
You have opened up quite a can of worms here, and one that is a bit off
topic from the original question and the Compact Framework. So before I go
deeper into the desktop CLR behavior (coming in the next paragraph) let me
just say to Jim and those who may be more interested in the practical CF
questions raised by the original post: all my statements about CF v1 and v2
behavior and suggestions still hold true. Jim, your original code is fine
for CF without any volatile, locks, etc. If you need your code to run
unmodified on both CF v1 and the desktop CLR, the simplest and best
performing way would be to use the System.Threading.Interlocked class. The
point that gets clarified below is that using "lock" can also be used to
achieve this goal, though at a higher cost.

<snip>

Thanks very much for the answer Brian - I was beginning to think I'd
been not only misleading myself, but also anyone who'd been reading my
web pages about threading!

Please pass on my thanks to Vance as well - that's either the third or
fourth time he's been extremely helpful when I've been having threading
confidence problems :)
 
Back
Top