[Mono-devel-list] Thread safety of readonly data members?
jonpryor at vt.edu
Thu Feb 19 06:52:24 EST 2004
On Wed, 2004-02-18 at 20:24, Michi Henning wrote:
> Hmmm... It's not uncommon for one thread to hold a pointer to a stack-
> allocated variable in another thread, so I guess the problem could
> arise in that case.
I've never seen this, and consider it an bizarre idea. The whole point
of having stack-allocated objects is so that you *don't* have to
lock/share them. Plus, I'd expect that you'd have difficulties ensuring
the the stack-allocated object lives long enough for the other thread to
*not* corrupt memory when the function exits scope...
> If Thread 2 previously has read a variable on the heap and
> the cache line containing that variable also happens to contain
> the instance of Class1, Thread 2 can read a stale value of _val
> when it calls getVal(), no?
Answer: no. I would suggest you pick up a book on hardware
architecture. I used "Parallel Computer Architecture: A
Hardware/Software Approach" by David E. Culler and Jaswinder Pal Singh
in my Computer Architecture classes. I won't call it wonderful (the
index is lacking in some ways), but it's thorough.
There are several ways for the hardware to ensure that stale values
don't remain within the cache lines, including:
- Bus Snooping
- Three-State MSI (Modified, Shared, Invalid) Write-Back Invalidation
- Four-State MESI (Modified, Exclusive-Clean, Shared, Invalid)
Write-Back Invalidation Protocol, which is used by all Pentium-Pro
and above Intel processors.
The hardware is designed to help you with cache coherence. The scenario
you're describing SHOULD NOT happen.
What you do need to worry about is that you have memory barriers when
you want them. It was my understanding that reading/writing to volatile
memory was a way of inserting memory barriers in C++.
> I've never been comfortable with the semantics of volatile. I agree,
> things should work correctly if something is marked as volatile,
> but I'm not sure the C++ standard actually guarantees that a memory
> barrier will be placed around a volatile access by the compiler.
> I think all that volatile guarantees is that memory will be read
> on access, so things will work correctly, for example, for memory-
> mapped registers. But I'm not sure that volatile guarantees memory
I don't think C++ provides any other mechanism within the standard.
Then again, C++ wasn't originally designed for a threaded environment,
and I keep reading articles implying that the next major version (C++
0x) will have additional features for threading, though they may just be
referring to the boost::threading libraries.
> And, of course, in C#, there is no volatile keyword, so I guess
> I still have to use a hard lock.
I see you answered this yourself already.
> Hmmm... Doesn't the language spec say that things will be initialized
> some time before they are accessed, but not necessarily on program
> startup? If the compiler generates code to do lazy initialization, I
> think things could still go wrong?
What the runtime does is out of our (the programmers) hands. So if the
runtime does the wrong thing, it's a runtime bug. The programmer needs
some assurance that const members will actually be initialized before
first use, or it's *impossible* to do *anything* reliably.
The runtime *must* ensure that const members are initialized in a
thread-safe manner, so that programs can't see the value change.
> Sure, but I'm not concerned about accessing the instance before it is
> constructed, but about accessing the contents of the instance after
> construction without holding a lock. In that case, I don't think the
> hardware can know that I might possibly be reading stale memory.
The hardware can know, as I alluded to above.
More information about the Mono-devel-list