multithreading : two easy questions

H

Harold Howe

Howdy,

1- Are property reads in effect volatile? Or is the compiler allowed to
optimize property reads away? ie

class foo
{
public int bar
{
get { return m_bar;}
set { m_bar = value;}
}
private int m_bar;
}

....

foo f = new foo();
f.bar=1000;
....// make f available to another thread
while (f.bar==1000)
{
...
}

On each pass through the loop, am I guaranteed that the compiler will
requery the get routine for the bar property? If so, then properties are
logically volatile. If not, then my loop will never end, even if a
background thread sets f.bar to a different value.

2- Are string assignments atomic? Hejlsberg's c# book claims that
assignments to ref types are atomic. Strings are references, but they
often don't feel like it. In searching these groups, I read several
posters that claim that string assignments are not atomic. Hence my doubt.

I am asking this question because I am trying to create a thread safe
object that has a string property. If string assignments are not atomic,
then returning a string value from a property getter is not thread safe,
and I will need a lock.

public String Value
{
get { return m_Value; // atomic??? }

// or
get
{
String result;
lock(this)
{
result = m_Value;
}
return result;
}
}

I would like to avoid the lock when reading if possible.

h^2

keywords: read, write, atomicity, assignment, properties.
 
J

Jon Skeet [C# MVP]

Harold Howe said:
1- Are property reads in effect volatile?

No. You need to synchronize them. This isn't to do with properties
though - it's to do with variables. The property can run perfectly
reasonably, but if the thread doesn't notice the new version of the
variable, the property will continue to return the old value.
2- Are string assignments atomic? Hejlsberg's c# book claims that
assignments to ref types are atomic. Strings are references, but they
often don't feel like it. In searching these groups, I read several
posters that claim that string assignments are not atomic. Hence my doubt.

They're atomic, but not necessarily volatile.
I am asking this question because I am trying to create a thread safe
object that has a string property. If string assignments are not atomic,
then returning a string value from a property getter is not thread safe,
and I will need a lock.

public String Value
{
get { return m_Value; // atomic??? }

// or
get
{
String result;
lock(this)
{
result = m_Value;
}
return result;
}
}

I would like to avoid the lock when reading if possible.

Well, for one thing you don't need to have a separate variable - you
can just return from within the lock. However, the above isn't thread-
safe - if another thread sets a different value for m_Value, there's no
guarantee that the first thread will see it. However, atomicity
requires that it will either see the old value or the new value - that
much you can rely on.

See http://www.pobox.com/~skeet/csharp/threads for more information.
 
H

Harold Howe

Jon said:
No. You need to synchronize them.

Where? Why? Here is a more complete example that actually shows a
background thread. The main thread sits and prints periods until the
background thread sets a property to 100.

Where is a lock necessary in this example? In light of the fact that
integer reads and writes are atomic, I see no need for a lock here. Even
though m_value is not volatile, aren't we guaranteed that the set
fuction will commit pending writes upon return? Please elaborate if you
disagree.

For the sake of discussion, assume the while loop can safely run one
full time while Value>=100.

using System;
using System.Threading;

namespace Test
{
internal class Test
{
static int m_value;
static int Value
{
get {return m_value;}
set {m_value = value;}
}

static void threadfunc()
{
for(int i=0; i<=100; ++i)
{
Value = i;
Thread.Sleep(100);
}
}

static void Main()
{
Console.WriteLine("Interlocked test.");
Thread thread = new Thread(new ThreadStart(threadfunc));
thread.Start();
while(Value != 100)
{
Console.Write('.');
}
}
}
}
The property can run perfectly
reasonably, but if the thread doesn't notice the new version of the
variable, the property will continue to return the old value.

Why wouldn't the thread notice the new value in the variable? I realize
that the private field is not volatile, but once the setter has
returned, aren't we guaranteed that all writes have been committed to
main memory?
(in reference to string atomicity)
However, the above isn't thread-
safe - if another thread sets a different value for m_Value, there's no
guarantee that the first thread will see it.

Could you explain why? I don't mean in the case where the property get
function was called, fetched the old value and was pre-empted by a
thread switch before it could return it. In this case, I understand that
the old value will still be returned. That I don't care about.

H^2
 
J

Jon Skeet [C# MVP]

Harold Howe said:

That's up to you - you could either make the properties themselves
thread-safe by including locking in there, or you can lock in the
calling code.

Because otherwise one thread can change the value of the variable (via
the property) and another thread might still see the old value because
there's nothing to say it can't unless you've got explicit memory
barriers in there.
Here is a more complete example that actually shows a
background thread. The main thread sits and prints periods until the
background thread sets a property to 100.

Where is a lock necessary in this example? In light of the fact that
integer reads and writes are atomic, I see no need for a lock here.

That's because you're confusing atomicity with volatility. They're very
different concepts.
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? The CLR doesn't make any such
guarantee - and even if the pending write was made, there's no
guarantee that the reading thread would make a fresh read rather than
using a cached version.
Please elaborate if you disagree.

See http://www.pobox.com/~skeet/csharp/threads/volatility.shtml
Why wouldn't the thread notice the new value in the variable? I realize
that the private field is not volatile, but once the setter has
returned, aren't we guaranteed that all writes have been committed to
main memory?

No, nor that fresh writes are read, either.
Could you explain why? I don't mean in the case where the property get
function was called, fetched the old value and was pre-empted by a
thread switch before it could return it. In this case, I understand that
the old value will still be returned. That I don't care about.

The JIT compiler may have enregistered the variable, for instance -
unless there's a thread barrier, there's nothing to say that the CLR
needs to read the newest value of the variable.

Please read the article I linked above (and in my previous post) - it
has much more information, and I don't want to repeat it all here.
 
H

Harold Howe

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.


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
 
J

Jon Skeet [C# MVP]

Harold Howe said:
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.
Sure.

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."

The important thing in there is "within a single thread of execution".
That doesn't say anything about what happens in different threads, or
when things are visible in other threads.
"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."

Again, this is within a single thread. In other words, it can't reorder

if (x==null || x.Length==0)

to try to access x.Length before testing whether x is null. There's no
guarantee about ordering of side-effects as seen by other threads.
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.

Although the method itself has no idea what's going to happen, it
doesn't need to - it doesn't guarantee that the write will be committed
to main memory until the next write memory barrier, which is fine -
another method can be responsible for that, if necessary.
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.

Consider inlined method calls which may end up enregistering variables.
Consider processor caches on multi-processor systems - the code may be
writing to main memory as far as it's concerned, but the cache may
decide not to write it back to the actual main memory until some other
code executes to make sure there's a write memory barrier. (This may
not happen on x86, but that's not to say it won't happen on other
processors...)
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.

Simple tests don't say what future implementations on different
processors. I agree that on current x86 processors, with the current
implementation, you're probably okay. I don't like to rely on
"probably" though.
On entry, the get method has no choice but to use a ldsfld IL
instruction to read the value from memory.

The IL isn't what's actually executed though - it's what the JIT
compiler decides to do that's important.
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.

I'm not addressing that case particularly - I'm addressing *all* cases.
There just *isn't* any guarantee that you'll see a write from one
thread in another one unless the appropriate memory barriers are there.
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.

I'm claiming that the spec doesn't guarantee it. I think most
implementations on most processors will be fine, but I prefer to go
with what the spec requires.

As an example of how extreme this can get, I was talking with someone
once about a multi-system (not just multi-processor) JVM implementation
once. "Main memory" there was accessed via the network - so nothing
wanted to read or write from/to "main memory" unless it absolutely had
to. The normal "main memory" of each system actually just acted as a
cache. Now obviously the memory model of the JVM is slightly different
to the .NET one, but the same kind of thing can apply.
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.

Yes, you can. However, you then need to think a bit about when you need
volatile and when you need a lock. I personally prefer to stick to
using locks all the time unless I find they're a significant
performance problem - which I never have.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top