473,396 Members | 1,860 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Volatile & Interlocked

Using the "volatile" keyword, creates a problem if I intend to use any of
the interlocked APIs. The compiler generates an error if I use the following
line, for example:

Interlocked.Increment(ref count);

The error says that a volatile field cannot be used as ref or out, but if I
don't use the volatile field, the value may be cached away in some method
that is just reading the field.

Consider, for example, an integer field being used by three threads. Two
threads intend to increment the value of the field while the third one just
wishes to check the value. Consider, for example, the initial value of the
field is 5.

If both the writer threads increment the value using the interlocked API,
the final value of the field is guaranteed to be 7. Without the use of the
interlocked API, the final value could be 6. Therefore, using the
interlocked API is a must in this case.

Without the field being marked as volatile, the reader thread may always see
the value as 5.

As can be seen, we need both the mechanisms under some cases.

What might be the solution for such situations?

Nov 16 '05 #1
14 7411
Hi...

Are you marking the field as "volatile"?

Just so we are clear, when you make a variable as volatile, it means that
there is a chance that the item could be changed asynchronously. In
general, if you control the threads, etc., you can simply use the "lock"
keyword:

lock(obj) {
// do work
}

If you need inter-process control, consider using a Mutex.
If you need multple readers with one writer, all banging away on the same
variable, consider the ReaderWriterLock class provided in the .NET framework
class library.

Hope this helps,
John Puopolo
If you have reader/writer threads are are looking to have multiple readers
with one writer, you can use the

"Pierre" <balioglu@DONOTSPAM_in.tum.de> wrote in message
news:Ow****************@TK2MSFTNGP10.phx.gbl...
Using the "volatile" keyword, creates a problem if I intend to use any of
the interlocked APIs. The compiler generates an error if I use the following line, for example:

Interlocked.Increment(ref count);

The error says that a volatile field cannot be used as ref or out, but if I don't use the volatile field, the value may be cached away in some method
that is just reading the field.

Consider, for example, an integer field being used by three threads. Two
threads intend to increment the value of the field while the third one just wishes to check the value. Consider, for example, the initial value of the
field is 5.

If both the writer threads increment the value using the interlocked API,
the final value of the field is guaranteed to be 7. Without the use of the interlocked API, the final value could be 6. Therefore, using the
interlocked API is a must in this case.

Without the field being marked as volatile, the reader thread may always see the value as 5.

As can be seen, we need both the mechanisms under some cases.

What might be the solution for such situations?

Nov 16 '05 #2
Pierre,

The lock keyword (Monitor.Enter and Monitor.Exit) has volatile
read/write semantics. You could use that instead of the Interlocked
class. It would be significantly easier to understand, but would be
slower to execute. The slower execution will not matter in most cases.

If you still wish to use the Interlocked class you'll be foreced to
remove the volatile modifier. I *think* the Interlocked class
implicitly creates a memory barrier. Can someone confirm? If so then
you can safely read the value using the Interlocked.CompareExchange
method.

int safeRead = Interlocked.CompareExchange(ref count, 0, 0);

Topics involving volatile read/writes, memory barriers, and the memory
model are very confusing. It's easy to make a mistake.

Brian

Pierre wrote:
Using the "volatile" keyword, creates a problem if I intend to use
any of the interlocked APIs. The compiler generates an error if I
use the following line, for example:

Interlocked.Increment(ref count);

The error says that a volatile field cannot be used as ref or out,
but if I don't use the volatile field, the value may be cached away
in some method that is just reading the field.

Consider, for example, an integer field being used by three threads.
Two threads intend to increment the value of the field while the
third one just wishes to check the value. Consider, for example, the
initial value of the field is 5.

If both the writer threads increment the value using the interlocked
API, the final value of the field is guaranteed to be 7. Without the
use of the interlocked API, the final value could be 6. Therefore,
using the interlocked API is a must in this case.

Without the field being marked as volatile, the reader thread may
always see the value as 5.

As can be seen, we need both the mechanisms under some cases.

What might be the solution for such situations?


Nov 16 '05 #3

"Brian Gideon" <br*********@yahoo.com> wrote in message
news:11**********************@o13g2000cwo.googlegr oups.com...
Pierre,

The lock keyword (Monitor.Enter and Monitor.Exit) has volatile
read/write semantics. You could use that instead of the Interlocked
class. It would be significantly easier to understand, but would be
slower to execute. The slower execution will not matter in most cases.

If you still wish to use the Interlocked class you'll be foreced to
remove the volatile modifier. I *think* the Interlocked class
implicitly creates a memory barrier. Can someone confirm? If so then
you can safely read the value using the Interlocked.CompareExchange
method.

int safeRead = Interlocked.CompareExchange(ref count, 0, 0);

Topics involving volatile read/writes, memory barriers, and the memory
model are very confusing. It's easy to make a mistake.

Brian


You are right, the Interlocked functions do create memory barriers with
aquire & release semantics, so there is no need for the volatile modifier.

Willy.
Nov 16 '05 #4

"Pierre" <balioglu@DONOTSPAM_in.tum.de> wrote in message
news:Ow****************@TK2MSFTNGP10.phx.gbl...
Using the "volatile" keyword, creates a problem if I intend to use any of
the interlocked APIs. The compiler generates an error if I use the
following line, for example:

Interlocked.Increment(ref count);

The error says that a volatile field cannot be used as ref or out, but if
I don't use the volatile field, the value may be cached away in some
method that is just reading the field.

Consider, for example, an integer field being used by three threads. Two
threads intend to increment the value of the field while the third one
just wishes to check the value. Consider, for example, the initial value
of the field is 5.

If both the writer threads increment the value using the interlocked API,
the final value of the field is guaranteed to be 7. Without the use of
the interlocked API, the final value could be 6. Therefore, using the
interlocked API is a must in this case.

Without the field being marked as volatile, the reader thread may always
see the value as 5.

As can be seen, we need both the mechanisms under some cases.

What might be the solution for such situations?


There's no need for the volatile modifier, the Win32 InterlockedXXX
functions called by Interlocked.XXXX(..) do insert memory barriers with
aquire/release semantics on X86.

Willy.
Nov 16 '05 #5
Willy Denoyette [MVP] <wi*************@pandora.be> wrote:
There's no need for the volatile modifier, the Win32 InterlockedXXX
functions called by Interlocked.XXXX(..) do insert memory barriers with
aquire/release semantics on X86.


Although you can then never just use the field directly - you need to
use the InterlockedXXX methods for *every* access to it. Otherwise,
there could be a memory barrier in the incrementing thread, but no
memory barrier in the reading thread.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #6

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Willy Denoyette [MVP] <wi*************@pandora.be> wrote:
There's no need for the volatile modifier, the Win32 InterlockedXXX
functions called by Interlocked.XXXX(..) do insert memory barriers with
aquire/release semantics on X86.


Although you can then never just use the field directly - you need to
use the InterlockedXXX methods for *every* access to it. Otherwise,
there could be a memory barrier in the incrementing thread, but no
memory barrier in the reading thread.


Sorry, the Win32 InterlockedXXX should read the CLR InterlockedXXX...

The InterlockedXXX operations (as implemented by the CLR) are atomic, there
is no problem for the reading thread.
The operations use the atomic asm instructions xadd, xchg, cmpxchg on single
CPU with lock prefix on SMP or multicores (X86)
Spinlocks are used to protect simultanious Interlocked operations on long's.
Note that Interlocked operations only serve correctly aligned pointer sized
types (32 & 64 bits).

Willy.
Nov 16 '05 #7
that info coming off the top of your head? or you are reading it from
somewhere? pray tell.

--
Regards
Alvin Bruney
[Shameless Author Plug]
The Microsoft Office Web Components Black Book with .NET
available at www.lulu.com/owc
--------------------------------------------------
"Willy Denoyette [MVP]" <wi*************@pandora.be> wrote in message
news:Od**************@TK2MSFTNGP15.phx.gbl...

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Willy Denoyette [MVP] <wi*************@pandora.be> wrote:
There's no need for the volatile modifier, the Win32 InterlockedXXX
functions called by Interlocked.XXXX(..) do insert memory barriers with
aquire/release semantics on X86.


Although you can then never just use the field directly - you need to
use the InterlockedXXX methods for *every* access to it. Otherwise,
there could be a memory barrier in the incrementing thread, but no
memory barrier in the reading thread.


Sorry, the Win32 InterlockedXXX should read the CLR InterlockedXXX...

The InterlockedXXX operations (as implemented by the CLR) are atomic,
there is no problem for the reading thread.
The operations use the atomic asm instructions xadd, xchg, cmpxchg on
single CPU with lock prefix on SMP or multicores (X86)
Spinlocks are used to protect simultanious Interlocked operations on
long's.
Note that Interlocked operations only serve correctly aligned pointer
sized types (32 & 64 bits).

Willy.

Nov 16 '05 #8
Willy Denoyette [MVP] <wi*************@pandora.be> wrote:

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Willy Denoyette [MVP] <wi*************@pandora.be> wrote:
There's no need for the volatile modifier, the Win32 InterlockedXXX
functions called by Interlocked.XXXX(..) do insert memory barriers with
aquire/release semantics on X86.


Although you can then never just use the field directly - you need to
use the InterlockedXXX methods for *every* access to it. Otherwise,
there could be a memory barrier in the incrementing thread, but no
memory barrier in the reading thread.


Sorry, the Win32 InterlockedXXX should read the CLR InterlockedXXX...

The InterlockedXXX operations (as implemented by the CLR) are atomic, there
is no problem for the reading thread.


You're missing something. You need a memory barrier in both the reading
thread *and* the thread which is changing the value.

Suppose I have the code:

int x = nonVolatileVariable;
....
int y = nonVolatileVariable;

where "..." consists of operations that the JIT knows don't change the
value of nonVolatileVariable. There's nothing to stop it from caching
the value, and making y the same as the initial value of x, even if
another thread has used InterlockedXXX to change the value during
"...".

InterlockedXXX makes sure that a value is read from main memory,
changed, and rewritten to main memory, all atomically. It *doesn't*
(and can't) make sure that all others threads *use* main memory to see
the value it's written.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #9

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Willy Denoyette [MVP] <wi*************@pandora.be> wrote:

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
> Willy Denoyette [MVP] <wi*************@pandora.be> wrote:
>> There's no need for the volatile modifier, the Win32 InterlockedXXX
>> functions called by Interlocked.XXXX(..) do insert memory barriers
>> with
>> aquire/release semantics on X86.
>
> Although you can then never just use the field directly - you need to
> use the InterlockedXXX methods for *every* access to it. Otherwise,
> there could be a memory barrier in the incrementing thread, but no
> memory barrier in the reading thread.
Sorry, the Win32 InterlockedXXX should read the CLR InterlockedXXX...

The InterlockedXXX operations (as implemented by the CLR) are atomic,
there
is no problem for the reading thread.


You're missing something. You need a memory barrier in both the reading
thread *and* the thread which is changing the value.

Suppose I have the code:

int x = nonVolatileVariable;
...
int y = nonVolatileVariable;

where "..." consists of operations that the JIT knows don't change the
value of nonVolatileVariable. There's nothing to stop it from caching
the value, and making y the same as the initial value of x, even if
another thread has used InterlockedXXX to change the value during
"...".


*** Sure, but here you assume that the JIT can cache the non-volatile member
field value in a CPU register, and as far as I can see (but I could be
wrong) this is not done in V1.x.
From what I see in the v1.1 JIT/codegen source code, registers are
exclusively used to cache locals not member fields. I will try to spend some
time to investigate the exact semantics of volatile in the CLR.

InterlockedXXX makes sure that a value is read from main memory,
changed, and rewritten to main memory, all atomically. It *doesn't*
(and can't) make sure that all others threads *use* main memory to see
the value it's written.


*** Note that v2.0 doesn't generate an error when using a volatile field
ref. in Interlocked.XXXX, it just generates following:

warning CS0420: xxxxxxx: a reference to a volatile field will not be treated
as volatile

it's clear the "reference" will not be treated as volatile but the field is
treated as volatile.

Willy.
Nov 16 '05 #10
Willy Denoyette [MVP] wrote:
*** Sure, but here you assume that the JIT can cache the non-volatile
member field value in a CPU register, and as far as I can see (but I
could be wrong) this is not done in V1.x.
From what I see in the v1.1 JIT/codegen source code, registers are
exclusively used to cache locals not member fields. I will try to
spend some time to investigate the exact semantics of volatile in the
CLR.

That might explain why it is nearly impossible for the problem in the
following code to manifest itself.

class Test
{
// To fix the problem this member should be marked as volatile.
private bool _Stop = false;

public void DoThreadStuff()
{
Thread t = new Thread(new ThreadStart(ThreadMethod));
t.Start();

Thread.Sleep(10000);

_Stop = true;
}

public void ThreadMethod()
{
int i = 0;
while (!_Stop)
{
i++;
}
}
}

It seems like a good idea to me to assume that any non-volatile member
could be cached. That way you are protected when you start running
your code on a new version of the framework that has a more aggressive
JIT optimizer.

*** Note that v2.0 doesn't generate an error when using a volatile
field ref. in Interlocked.XXXX, it just generates following:

warning CS0420: xxxxxxx: a reference to a volatile field will not be
treated as volatile

it's clear the "reference" will not be treated as volatile but the
field is treated as volatile.


Interesting. I'm still trying to determine if this a good a idea or
not.

Brian

Nov 16 '05 #11
Willy Denoyette [MVP] <wi*************@pandora.be> wrote:
You're missing something. You need a memory barrier in both the reading
thread *and* the thread which is changing the value.

Suppose I have the code:

int x = nonVolatileVariable;
...
int y = nonVolatileVariable;

where "..." consists of operations that the JIT knows don't change the
value of nonVolatileVariable. There's nothing to stop it from caching
the value, and making y the same as the initial value of x, even if
another thread has used InterlockedXXX to change the value during
"...".


*** Sure, but here you assume that the JIT can cache the non-volatile member
field value in a CPU register, and as far as I can see (but I could be
wrong) this is not done in V1.x.
From what I see in the v1.1 JIT/codegen source code, registers are
exclusively used to cache locals not member fields. I will try to spend some
time to investigate the exact semantics of volatile in the CLR.


If you're going to go by what the current JIT does rather than what the
specification says, there are any number of things which could work - I
suspect double-checked locking works in the current implementation, for
instance.
InterlockedXXX makes sure that a value is read from main memory,
changed, and rewritten to main memory, all atomically. It *doesn't*
(and can't) make sure that all others threads *use* main memory to see
the value it's written.


*** Note that v2.0 doesn't generate an error when using a volatile field
ref. in Interlocked.XXXX, it just generates following:

warning CS0420: xxxxxxx: a reference to a volatile field will not be treated
as volatile

it's clear the "reference" will not be treated as volatile but the field is
treated as volatile.


Right. Interesting.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #12

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Willy Denoyette [MVP] <wi*************@pandora.be> wrote:
> You're missing something. You need a memory barrier in both the reading
> thread *and* the thread which is changing the value.
>
> Suppose I have the code:
>
> int x = nonVolatileVariable;
> ...
> int y = nonVolatileVariable;
>
> where "..." consists of operations that the JIT knows don't change the
> value of nonVolatileVariable. There's nothing to stop it from caching
> the value, and making y the same as the initial value of x, even if
> another thread has used InterlockedXXX to change the value during
> "...".


*** Sure, but here you assume that the JIT can cache the non-volatile
member
field value in a CPU register, and as far as I can see (but I could be
wrong) this is not done in V1.x.
From what I see in the v1.1 JIT/codegen source code, registers are
exclusively used to cache locals not member fields. I will try to spend
some
time to investigate the exact semantics of volatile in the CLR.


If you're going to go by what the current JIT does rather than what the
specification says, there are any number of things which could work - I
suspect double-checked locking works in the current implementation, for
instance.


Agreed, but the specification is a little confusing at best.
I guess you are talking about the C# Language (and/or the C# programmers
reference?) spec's. (IMO this doesn't even belong to the C# spec's at all).

From these, it's clear that volatile prevents reordering of the volatile
fields by the compiler, but it doesn't clearly state that it :
- prevents reads and writes to be cached in registers, the C# programmers
reference is a bit more explicit though (As I said before, IMO the v1.x JIT
doesn't cache fields in registers on X86).
- prevents combining read or write operations (I assume it does).
- prevents optimizations of non volatile variables relative to the volatiles
(here I assume it doesn't). For example, a write to a non volatile that
precedes a read from a volatile might be moved to execute after the read.
- it doesn't prevent reordering by the CPU hardware (Here I'm sure it
doesn't)
- guarantees that all CPU's see memory accesses in the same order (IMO not
possible)

Add to (my) confusion that:
VB.NET and J# do not support volatile - I wonder why?,
The C++ volatile specification is simply a description of the C compilers
implementation of volatile.
Different behavior, in both compiler and framework versions, when using
volatile fields in Interlocked class methods.
For me enough reasons not to rely on 'volatile' and prefer to use the
synchronization primitives offered by the framework, and that's your point I
agree with, use Interlocked methods to 'read' the an interlocked variable.

Willy.


Nov 16 '05 #13

"Willy Denoyette [MVP]" <wi*************@pandora.be> wrote in message
news:Oz**************@TK2MSFTNGP15.phx.gbl...
synchronization primitives offered by the framework, and that's your point
I agree with, use Interlocked methods to 'read' the an interlocked
variable.


Or simply the System.Threading.Thread.VolatileRead methods.

Willy.
Nov 16 '05 #14
Willy Denoyette [MVP] <wi*************@pandora.be> wrote:
If you're going to go by what the current JIT does rather than what the
specification says, there are any number of things which could work - I
suspect double-checked locking works in the current implementation, for
instance.
Agreed, but the specification is a little confusing at best.
I guess you are talking about the C# Language (and/or the C# programmers
reference?) spec's. (IMO this doesn't even belong to the C# spec's at all).


No - I'm talking about the CLR spec along with the C# spec.
From these, it's clear that volatile prevents reordering of the volatile
fields by the compiler, but it doesn't clearly state that it :
- prevents reads and writes to be cached in registers, the C# programmers
reference is a bit more explicit though (As I said before, IMO the v1.x JIT
doesn't cache fields in registers on X86).
I think the C# spec says all that's needed, actually. Section 10.10 of
the ECMA spec:

<quote>
Execution shall proceed such that the side effects of each
executing thread are preserved at critical execution points. A side
effect is defined as a read or write of a volatile field, a write to a
non-volatile variable, a write to an external resource, and the
throwing of an exception. The critical execution points at which the
order of these side effects must be preserved are references to
volatile fields (§17.4.3), lock statements (§15.12), and thread
creation and termination.
</quote>

When the spec later talks about reordering, it is talking about
reordering the writes and reads in the memory model - this isn't
necessarily the order that the processor issues the instructions in,
due to caches etc.
Add to (my) confusion that:
VB.NET and J# do not support volatile - I wonder why?,
I suspect it's because volatility is a really tricky way of achieving
thread-safety. Locks are normally much easier to sort out.
The C++ volatile specification is simply a description of the C compilers
implementation of volatile.
Different behavior, in both compiler and framework versions, when using
volatile fields in Interlocked class methods.
For me enough reasons not to rely on 'volatile' and prefer to use the
synchronization primitives offered by the framework, and that's your point I
agree with, use Interlocked methods to 'read' the an interlocked variable..


I'd prefer to use straight locks unless I absolutely *knew* that they
would be a performance problem, and I had a lot of time to really
convince myself that declaring a variable as being volatile would be
good enough.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #15

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

15
by: DanGo | last post by:
Hi All, I'm trying to get my head around synchronization. Documentation seems to say that creating a volatile field gives a memorybarrier. Great! But when I do a little performance testing...
22
by: Assaf | last post by:
hi all i know that i should not cross-post, but i am not sure to which group to post this question. 2 quesions about volatile: 1. i use volatile when 2 threads access the same variable...
10
by: Lau Lei Cheong | last post by:
Hello, I really need to use volatile System.Int64 for a .NET v1.1 program in C#. But the compiler complains "a volatile field can not be of type long". How to work around it? Or is there any...
3
by: Ryan Liu | last post by:
Hi, Can some one tell the criteria I can used to decide use of Interlocked.Increment() vs volatile , which is better? Thanks a lot! Ryan
3
by: Amir Shitrit | last post by:
Hello. How come it's safe to read non-volatile fields that are shared across threads using locks for synchronization (for example, Monitor.Enter or EventWaitHandle), but it's not safe to access...
94
by: Samuel R. Neff | last post by:
When is it appropriate to use "volatile" keyword? The docs simply state: " The volatile modifier is usually used for a field that is accessed by multiple threads without using the lock...
5
by: Mark Salsbery [MVP] | last post by:
I have an member variable (int) that is accessed by multiple threads using Interlocked.Increment(), Interlocked.Decrement(), and read directly. Using volatile gives me "CS0420: a reference to a...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.