Re: Named shared memory without synchronization
"Dan Schwartz" wrote:
I have the following scenario:
A primitive (integer) lives in a shared memory page.
Process 1: reads it every once in a while
Process 2: writes to to it fairly often
Since this is an int, my assumption was that this scenario
would not benefit
from synchronization, as an int in the C language is
defined (if I'm not
mistaken) as the
width of the CPU register, thus being atomic and
uncorruptable.
This is correct. Actually, there is no strict requirement in
C language that `int' should be equal to CPU register.
Here's the quote from the C Standard:
<quote>
6.2.5 Types
5 [...] A "plain" int object has the natural size suggested
by the architecture of the execution environment (large
enough to contain any value in the range INT_MIN to INT_MAX
as defined in the header <limits.h>).
</quote>
So, theoretically `int' can be larger that CPU register.
However, I didn't encounter yet any 32-bit implementation
where `int' isn't equal to CPU register. Probably in a world
of embedded devices there are some.
Several articles I've seen on the net however, maintained
that I need to
declare the primitive as volatile (which makes sense to
me) and aligned to a
word boundry (which doesn't make sense to me).
As you already figured out `volatile' specifier is required
in order to tell the compiler that it should not assume any
optimizations regarding a variable. Alignment is important
because unaligned variable may require more than one
instruction to access it, therefore breaching atimicity of
an access. Here's good article about alignment:
"Windows Data Alignment on IPF, x86, and x64"
http://msdn.microsoft.com/library/en-us/dv_vstechart/html/vcconWindowsDataAlignmentOnIPFX86X86-64.asp
Accessing unaligned data is discussed in section "Why Is
Alignment a Concern?".
After implementing the above scenario, it became apparent
that the compiler
doesn't need the volatile declaration. The integer seems
to be fetched again
for every access. In general, after substantial testing, I
haven't found
drawbacks to this no-lock strategy. This, of course, means
nothing. Nothing
can ever be validated with testing when dealing with
synchronization issues.
My question(s):
Is this really a stable solution?
No. I'd suggest to use `volatile' specifier, so compiler
will be aware of possibility of asynchronous changes. In
your specific case optimizer didn't kick in for whatever
reason, but I wouldn't rely on that in the future.
Does the compiler know that the integer lives in a shared
page and becomes
'implicitly' volatile?
No, compiler doesn't have any chance to know about that.
That's why `volatile' specifier was invented in first place.
If not, does this mean that the same startegy would work
for thread
synchronization of an integral global variable?
Integral global variable can be used for thread
synchronization without a problem. Such solution may seem
dirty, since there is plenty of synchronization facilities
in Windows system. Nevertheless, it can be done with global
`int', too.
What about alignment, what would be the reason to worry
about it for
primitive types?
The reason is that unaligned primitive types can become not
so primitive and access to them will require several
instructions. It explained well in above mentioned article.
HTH
Alex