Re: C#, Threads, Events, and DataGrids/DataSets

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance

From: Jon Skeet [C# MVP] (skeet_at_pobox.com)
Date: 02/25/04


Date: Wed, 25 Feb 2004 09:13:23 -0000

Valery Pryamikov <Valery.Pryamikov@invalid.sm.siemens.no.nospam> wrote:
> Jon, for God sake, go read some docs and try to reflect it!

Um, I *have* read the specification. I have seen no guarantee of the
type you're implying exists.

> JIT compiler just compiles IL to x86 (or whatever platform it is developed
> for).

Yup.

> Some optimizing compilers could optimize away loading variable into register
> for cycles with trivial cycle body as optimization technique, but no
> compiler will do it for non-trivial cycle body (there are books on compiler
> optimization theory if you are interesting).

They could, however. That's the point - they could, and on some
architectures they may do. Yes, it won't be a problem on x86, but I
don't believe the spec guarantees it won't be *in general*.

> Volatile has several meanings
> (overloaded semantic) and one of these meanings is to signal optimizing
> compiler that it can't use that particular type of optimization.

No, it's more than that. Volatile in the .NET CLI has a very clear
meaning, to do with memory barriers. A volatile read/write affects more
than just the variable being read/written - it affects the whole
"stream" of memory accesses.

> However any
> non-inlined method call is one of the criteria that rules off that
> optimization too (non-trivial cycle body) and delegate call is never inlined
> (not speaking about other things).

I don't see where inlining is actually relevant here.

> Other meaning of volatile is defined by .Net spec where it adds
> release/acquire semantic for variable reads/writes.

That's the meaning I'm talking about, seeing as I'm talking about the
specification.

> This is important only
> for non-trivial memory objects with non atomic assignment and consistency
> requirements. For example if we speak of some class that has some instance
> fields, then volatile could be important to guarantee that all memory writes
> from class constructor will be completed before memory read on 'this'. But
> with usage pattern that we discuss here it could never make that problem. I
> can even give you exact prove of this fact based both on x86 and .Net memory
> models (but I rather would not do it for not wasting time of the newsgroup
> readers on something they probably isn't interesting to read anyhow).

Any proof *cannot* be based on the x86 memory model, as the .NET memory
model doesn't refer to the x86 memory model at all, and is indeed much
weaker than it.

> As I already said - regardless of processor architecture and memory model,
> it is always guaranteed that memory write from one thread will be seen by
> all other threads. This is a general rule of computing. period.

Not really. The general rule (to my mind) is that there is some way of
enforcing visibility, but that's not necessary what happens
immediately.

> Order isn't guaranteed, but visibility is!

Nope. It really isn't - not without memory barriers. If you're saying
that there isn't a single memory model which pretty much explicitly
states that the code posted might not work, I refer you to the Java
memory model. Choice quotes are:

<quote>
Best practice is that if a variable is ever to be assigned by one
thread and used or assigned by another, then all accesses to that
variable should be enclosed in synchronized methods or synchronized
statements.
</quote>

<quote>
Each thread has a working memory, in which it may keep copies of the
values of variables from the main memory that is shared between all
threads. To access a shared variable, a thread usually first obtains a
lock and flushes its working memory. This guarantees that shared values
will thereafter be loaded from the shared main memory to the threads
working memory. When a thread unlocks a lock it guarantees the values
it holds in its working memory will be written back to the main memory.
</quote>

Now, as I said before, the Java memory model isn't quite the same as
the CLI memory model, but both are relatively weak in terms of the
guarantees they give.

Here's another quote, this time from .NET - the Thread.MemoryBarrier
method documentation:

<quote>
Synchronizes memory. In effect, flushes the contents of cache memory to
main memory, for the processor executing the current thread.
</quote>

Now, that suggests that there is the idea of a "cache" and "main
memory" and that they won't necessarily be in sync. Some kind of
flushing may be required in some situations. Where is the *guarantee*
that such a flush occurs in the posted code?

> Jon, I've used several years of my life learning and programming symmetric
> multiprocessing and I'm not going to argue here with you about things that
> you apparently don't know well. You can have you last word if you want,
> however be warned that trying to argue about something that you are not
> really familiar could just harm your reputation as a specialist.

If it really is guaranteed, why not just post the relevant parts of the
the CLI specification? If I really am wrong, I'd *really* like to be
proven wrong. For one thing, it would make my life easier when writing
similar code!

I'm certainly *not* an expert in the x86 memory model, or indeed any
specific processor's memory model. I wouldn't even say I'm an *expert*
in the CLI memory model, although I know more about that than about any
specific processor model.

I'm not trying to argue that under the current .NET implementation, the
posted code won't always work. It may well work for all future
implementations on every architecture, too - but I don't believe it's
guaranteed to. All I'm after is some evidence of that guarantee, or an
acknowledgement that it doesn't exist.

-- 
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too


Relevant Pages

  • Re: When is "volatile" used instead of "lock" ?
    ... with respect to the memory model. ... Where else is it violating the 335 memory ... can still write thread-safe code. ... IAsyncResult result = BeginBackgroundOperation(ref value1, ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: C#, Threads, Events, and DataGrids/DataSets
    ... Volatile has meanings both for compiler and runtime. ... Non-inlined method call makes cycle body to be considered ... When I said that I can give prove for both x86 and .Net memory models I ... > model doesn't refer to the x86 memory model at all, ...
    (microsoft.public.dotnet.general)
  • Re: C- Programming for ARM Microcontrollers
    ... long as it's just the memory allocation directives, ... a '#define far' (their excuse for not having to use Huge memory model ... Well huge model does generate less efficient code but as I remember the ...
    (comp.arch.embedded)
  • Re: C#, Threads, Events, and DataGrids/DataSets
    ... Atomic assignment has everything to do with it - read on ... flushing them back to the main processor memory. ... The Java memory model makes all of this somewhat clearer, ... So where is the guarantee that writes are seen immediately? ...
    (microsoft.public.dotnet.general)
  • Re: Randall Hydes essay "Which assembler is the best?"
    ... >>the flat memory model. ... I'd say that there is no such thing as "flat ... use the segmented nature of the x86 memory model: It sets up the FS segment ...
    (alt.lang.asm)