Clarification on the applicability of compile-time optimization to astruct variable which encompasse

M

Myth__Buster

#include <stdio.h>

struct InterruptData
{
int numberOfInterrupts;
volatile int timer;
int numberOfTimesInterruptsMasked;
} InterruptMonitor;


/*
* Interrupt handler code.
*/

int main(void)
{
InterruptMonitor = InterruptMonitor;

printf("\n LOG - InterruptMonitor.numberOfInterrupts : %d \n",
InterruptMonitor.numberOfInterrupts);

printf("\n LOG - InterruptMonitor.timer : %d \n",
InterruptMonitor.timer);

printf("\n LOG - InterruptMonitor.numberOfTimesInterruptsMasked : %d \n",
InterruptMonitor.numberOfTimesInterruptsMasked);

return 0;
}

-------------

InterruptMonitor = InterruptMonitor; - Should this be a candidate for compile-time optimization in spite of having a field qualified as volatile?

Cheers,
Raghavan Santhanam
 
B

Ben Bacarisse

Myth__Buster said:
#include <stdio.h>

struct InterruptData
{
int numberOfInterrupts;
volatile int timer;
int numberOfTimesInterruptsMasked;
} InterruptMonitor;


/*
* Interrupt handler code.
*/

int main(void)
{
InterruptMonitor = InterruptMonitor;
return 0;
}

-------------

InterruptMonitor = InterruptMonitor; - Should this be a candidate for
compile-time optimization in spite of having a field qualified as
volatile?

I fear that your example may be one "a bit like" the code you really
care about, but I have to talk about what you post...

To a very large extent, the C standard washes it hands of volatile
objects. Sure, it says a fair bit about what *may* happen but it also
says "[w]hat constitutes an access to an object that has volatile-
qualified type is implementation-defined" (6.7.3 p7) and "[a]n actual
implementation need not evaluate part of an expression if it can deduce
that [...] no needed side effects are produced (including any caused by
[...] accessing a volatile object)" (5.1.2.3 p4).

Together, these give an implementation so much leeway that you often
need to refer to the implementation, not the standard. For example, an
implementation may well be able to deduce that the assignment is not a
"needed side effect", coming as it does at the start of main. Equally,
an implementation may treat all accesses to volatile-qualified objects
with kid gloves.
 
U

Uncle Steve

Myth__Buster said:
#include <stdio.h>

struct InterruptData
{
int numberOfInterrupts;
volatile int timer;
int numberOfTimesInterruptsMasked;
} InterruptMonitor;


/*
* Interrupt handler code.
*/

int main(void)
{
InterruptMonitor = InterruptMonitor;
return 0;
}

-------------

InterruptMonitor = InterruptMonitor; - Should this be a candidate for
compile-time optimization in spite of having a field qualified as
volatile?

I fear that your example may be one "a bit like" the code you really
care about, but I have to talk about what you post...

To a very large extent, the C standard washes it hands of volatile
objects. Sure, it says a fair bit about what *may* happen but it also
says "[w]hat constitutes an access to an object that has volatile-
qualified type is implementation-defined" (6.7.3 p7) and "[a]n actual
implementation need not evaluate part of an expression if it can deduce
that [...] no needed side effects are produced (including any caused by
[...] accessing a volatile object)" (5.1.2.3 p4).

Together, these give an implementation so much leeway that you often
need to refer to the implementation, not the standard. For example, an
implementation may well be able to deduce that the assignment is not a
"needed side effect", coming as it does at the start of main. Equally,
an implementation may treat all accesses to volatile-qualified objects
with kid gloves.

This is a concern in my mind right now as I'm writing some posix
threads code, and so obviously there are a large number of variables
which ought to be declared volatile. I don't have a copy of the
standard, so I was wondering whether the volatile attribute is
inherited by structures contained within a structure declared
volatile. Example:


struct substruct {
int a, b;
};

struct container {
int n_coord;
struct substruct coord[];
};


volatile struct container c;

The question is, does c.coord.a have the volatile attribute?



Regards,

Uncle Steve
 
U

Uncle Steve

To a very large extent, the C standard washes it hands of volatile
objects. Sure, it says a fair bit about what *may* happen but it also
says "[w]hat constitutes an access to an object that has volatile-
qualified type is implementation-defined" (6.7.3 p7) and "[a]n actual
implementation need not evaluate part of an expression if it can deduce
that [...] no needed side effects are produced (including any caused by
[...] accessing a volatile object)" (5.1.2.3 p4).

Together, these give an implementation so much leeway that you often
need to refer to the implementation, not the standard. For example, an
implementation may well be able to deduce that the assignment is not a
"needed side effect", coming as it does at the start of main. Equally,
an implementation may treat all accesses to volatile-qualified objects
with kid gloves.

This is a concern in my mind right now as I'm writing some posix
threads code, and so obviously there are a large number of variables
which ought to be declared volatile.

What leads you to that conclusion? That line of though usually implies
you are misunderstanding the relationship between volatile and threads.

What are you trying to achieve with volatile?

Well, I have some data structures that will be accessed from arbitrary
threads, so I want to make sure there's no funny business happening
behind the scenes where the compiler decides that certain accesses are
optional.

Here's a little snippet of code which shows the issue, albeit without
nested structures:


#include <local_time.h>


struct sample_s {
T64 a, b;
};

typedef struct sample_s sample;

#define SAMPLES 100



#define nsclock(p) { \
volatile struct timespec T; \
clock_gettime(CLOCK_MONOTONIC, &T); \
p = T.tv_sec * 1000000000 + T.tv_nsec; \
}

void do_timing(sample * p)
{
volatile T64 s, e, v;
// volatile unsigned int i;

nsclock(s);
nsclock(s);

// for(i = 0; i < 1 ; i++);
nsclock(e);

p->a = (e - s);

nsclock(e);

p->b = (e - s);

return;
}


void emit_sample(sample *p)
{
fprintf(stdout, "%-5d %-5d %-5d\n", p->a, p->b, p->b - p->a);

return;
}




int main(char *argv, int argc)
{
sample tr[SAMPLES + 1];
int i;

tr[SAMPLES].a = tr[SAMPLES].b = 0;


for(i = 0; i < SAMPLES; i++)
do_timing(&tr);

fprintf(stdout, "Timing results for %d samples:\n\n", SAMPLES);

fprintf(stdout, "%-5s %-5s %-5s\n", "A", "B", "B - A");

for(i = 0; i < SAMPLES; i++)
emit_sample(&tr);

exit(0);
}


So, without including all the crap in local_time.h, I have to explain
a few definitions.

T64 is an unsigned long long int representing microseconds since
epoch, but I ended up using it as if it represented nanoseconds since
epoch since my i3 dual core laptop has a nanosecond-resolution timer.

The variable declared volatile are required otherwise some variable
accesses are optimized out, giving inaccurate results during the data
acquisition phase. The problems here are magnified when these access
patterns occur with competing threads. IIRC, mutexes are not memory
access barriers and solve different problems.


Regards,

Uncle Steve
 
U

Uncle Steve

On 07/ 7/12 05:08 AM, Uncle Steve wrote:
[...]
This is a concern in my mind right now as I'm writing some posix
threads code, and so obviously there are a large number of variables
which ought to be declared volatile.

What leads you to that conclusion? That line of though usually implies
you are misunderstanding the relationship between volatile and threads.

What are you trying to achieve with volatile?

Well, I have some data structures that will be accessed from arbitrary
threads, so I want to make sure there's no funny business happening
behind the scenes where the compiler decides that certain accesses are
optional.

Although the latest "C11" Standard adds some multi-threading
support, I'll ignore that because (1) C11 implementations are not
exactly thick upon the ground as yet, (2) you mentioned you're
using Pthreads anyhow, and (3) I haven't studied the C11 threading
stuff closely enough to be a competent commentator. ;-)

So: As long as you're using an established non-C-specific
threading framework, I suggest you visit comp.programming.threads,
a newsgroup devoted to multi-threading issues. There you will learn
that `volatile' is neither necessary *nor* sufficient in connection
with variables shared between threads. (You needn't take my word on
this: Just browse the comp.programming.threads archives and you'll
see the local experts refuting this misunderstanding every couple
weeks. It's comp.programming.threads' equivalent of `void main'.)

Or, as my first threading teacher put it, "Don't Do That."

Is there are C standard threading framework?

Threaded code is a de-facto reality in today's multi-core environment.
Save for the embedded sector, most systems will run threads in
parallel, and that is that. C has to recognize this watershed moment
in the refinement of the language.

While the specifics of an implementation within a given operating
system are not C issues, certain common optimizations can be a problem
with certain algorithms, and so there ought to be a C solution to the
problem. What is it about the volatile attribute that makes it
insufficient in your mind to the problem presented by threaded code?


Regards,

Uncle Steve
 
U

Uncle Steve

On 7/6/2012 2:01 PM, Uncle Steve wrote:
08 AM, Uncle Steve wrote:
[...]
This is a concern in my mind right now as I'm writing some posix
threads code, and so obviously there are a large number of variables
which ought to be declared volatile.
o
What leads you to that conclusion? That line of though usually implies
you are misunderstanding the relationship between volatile and threads.

What are you trying to achieve with volatile?

Well, I have some data structures that will be accessed from arbitrary
threads, so I want to make sure there's no funny business happening
behind the scenes where the compiler decides that certain accesses are
optional.

Although the latest "C11" Standard adds some multi-threading
support, I'll ignore that because (1) C11 implementations are not
exactly thick upon the ground as yet, (2) you mentioned you're
using Pthreads anyhow, and (3) I haven't studied the C11 threading
stuff closely enough to be a competent commentator. ;-)

So: As long as you're using an established non-C-specific
threading framework, I suggest you visit comp.programming.threads,
a newsgroup devoted to multi-threading issues. There you will learn
that `volatile' is neither necessary *nor* sufficient in connection
with variables shared between threads. (You needn't take my word on
this: Just browse the comp.programming.threads archives and you'll
see the local experts refuting this misunderstanding every couple
weeks. It's comp.programming.threads' equivalent of `void main'.)

Or, as my first threading teacher put it, "Don't Do That."

Is there are C standard threading framework?

Yes, read C11. If you are familiar with pthreads, you'll see where most
of the new primitives originate.

Well, I don't follow gcc development, so I don't know when those
features will be available on my system.
Only if you incorporate threads in your code either explicitly or
implicitly with something like OpenMP.

Well, sure, but I'd like to think that multithreaded applications will
be popular. It helps to improve the interactivity of applications
with a GUI frontend for one thing, never mind what you can do with
message-passing interfaces or asynchronus network I/O threads.

O.K., so do nested structure elements inherit the parent structure's
volatile attribute?
Given you are the one going against conventional wisdom, what in your
mind makes volatile a solution to the problem presented by threaded code?

In addition, what is "the problem presented by threaded code"?

Well, code optimization from global CSE might eliminate memory
accesses to variable that could be modified by other threads in ways
that affect the algorithm. Depends of the code.


Regards,

Uncle Steve
 
U

Uncle Steve

On 07/ 7/12 05:08 AM, Uncle Steve wrote:
This is a concern in my mind right now as I'm writing some posix
threads code, and so obviously there are a large number of variables
which ought to be declared volatile.
What leads you to that conclusion?  That line of though usually implies
you are misunderstanding the relationship between volatile and threads.
What are you trying to achieve with volatile?

Well, I have some data structures that will be accessed from arbitrary
threads, so I want to make sure there's no funny business happening
behind the scenes where the compiler decides that certain accesses are
optional.

[snip]

The variable declared volatile are required otherwise some variable
accesses are optimized out, giving inaccurate results during the data
acquisition phase.  The problems here are magnified when these access
patterns occur with competing threads.  IIRC, mutexes are not memory
access barriers and solve different problems.

To be topical, here's the answer for C11: volatile is useless as a
portable threading construct. Do not use it. It's (maybe) useful in a
portable way only for 3 obscure situations: MMIO, setjmp and longjmp
stuff, and signal handling. If you properly use C11 mutexes, there is
absolutely no need for volatile. To paraphrase you else-thread, there
will be no "funny business" if you use mutexes correctly. It tells the
compiler, the hardware, and anything else relevant, to obey the
semantics of the mutex. volatile is similarly useless when you
correctly use the new "weak" C11 atomics. volatile adds nothing
(portably).

Now, to finally answer your question, C11 threading semantics,
including the lack of useful volatile semantics, is basically copied
wholesale from pthreads. Don't use volatile as a portable threading
construct with pthreads either. pthread mutexes do everything you
need. volatile adds absolutely nothing (portably).

(Yes, you can accomplish useful code with volatile for specific
platform and specific compilers with specific settings. That's an
"advanced" topic that I won't cover now.)

Now, what do you mean by "mutexes are not memory access barriers"?
Mutexes do two things: they provide blocking semantics for mutual
exclusion, and they guarantee visibility ala the usual "happens-
before" semantics. Mutexes are implemented with hardware memory
fences / barriers. This is all true for mutexes in pthreads, win32
threads, Boost threads, ACE threads, C11 threads, C++11 threads, and
every case I can recall seeing the word "mutex".

Well, mutexes are barriers for the memory accesses associated with the
mutex itself, but not in general. Reading the above I can tell that
you think I'm using POSIX mutexes, however that is not the case. I am
using a custom locking scheme that allows for concurrent readers, but
is exclusive for writers. As a consequence, the behavior of
variables marked volatile in my code is critical, so I don't want to
mistakenly use it in a way that results in surprises.

Now you can say that what I am doing is non-portable, but you would
be wrong there since my algorithms are in fact portable as long as I
am following the rules of the C standard. Perhaps the proper term is
limited portability as I rely on a tiny amount of platform specific
asm. (One instruction.)


Regards,

Uncle Steve
 
I

Ian Collins

To a very large extent, the C standard washes it hands of volatile
objects. Sure, it says a fair bit about what *may* happen but it also
says "[w]hat constitutes an access to an object that has volatile-
qualified type is implementation-defined" (6.7.3 p7) and "[a]n actual
implementation need not evaluate part of an expression if it can deduce
that [...] no needed side effects are produced (including any caused by
[...] accessing a volatile object)" (5.1.2.3 p4).

Together, these give an implementation so much leeway that you often
need to refer to the implementation, not the standard. For example, an
implementation may well be able to deduce that the assignment is not a
"needed side effect", coming as it does at the start of main. Equally,
an implementation may treat all accesses to volatile-qualified objects
with kid gloves.

This is a concern in my mind right now as I'm writing some posix
threads code, and so obviously there are a large number of variables
which ought to be declared volatile.

What leads you to that conclusion? That line of though usually implies
you are misunderstanding the relationship between volatile and threads.

What are you trying to achieve with volatile?
 
U

Uncle Steve

Then use your platform's native threading primitives.

Doing so would incur a performance penalty in comparison to my
synchronization primitives in some circumstances.
There already are.

Yes. There are many examples of such code.
A volatile T is a volatile T no matter what it contains.

Look. In threaded applications, the truth associated with the value
associated with certain variables can be somewhat indeterminate. If
that's true in your code, you might want to be aware of it.
If the code depends on volatile, it is broken. Use the atomics or
synchronisation primitives provided by the language or platform. They
exist for a reason.

You aren't listening to me.



Regards,

Uncle Steve
 
E

Eric Sosman

[...]
This is a concern in my mind right now as I'm writing some posix
threads code, and so obviously there are a large number of variables
which ought to be declared volatile.

What leads you to that conclusion? That line of though usually implies
you are misunderstanding the relationship between volatile and threads.

What are you trying to achieve with volatile?

Well, I have some data structures that will be accessed from arbitrary
threads, so I want to make sure there's no funny business happening
behind the scenes where the compiler decides that certain accesses are
optional.

Although the latest "C11" Standard adds some multi-threading
support, I'll ignore that because (1) C11 implementations are not
exactly thick upon the ground as yet, (2) you mentioned you're
using Pthreads anyhow, and (3) I haven't studied the C11 threading
stuff closely enough to be a competent commentator. ;-)

So: As long as you're using an established non-C-specific
threading framework, I suggest you visit comp.programming.threads,
a newsgroup devoted to multi-threading issues. There you will learn
that `volatile' is neither necessary *nor* sufficient in connection
with variables shared between threads. (You needn't take my word on
this: Just browse the comp.programming.threads archives and you'll
see the local experts refuting this misunderstanding every couple
weeks. It's comp.programming.threads' equivalent of `void main'.)

Or, as my first threading teacher put it, "Don't Do That."
 
U

Uncle Steve

I strongly suggest that you don't use the word "mutex" for your code
because you will confuse most readers. Most readers will associate
"mutex" with both mutual exclusion and "happens-before" global memory
visibility. That's how the term has been commonly used (ex: posix
pthreads), and how it will continue to commonly be used (ex: C11).


I will say it again: the C89 and C99 standards do not mean what you
think. What the compiler writers and thread library writers understand
volatile to mean is not what you understand volatile to mean, and at
the end of the day what the compiler writers and thread library
writers think is paramount. You may be able to get this to work for
specific platforms with specific compilers. I suggest you ask in a
location specific to such implementations for such platform specific
hackery. However, do not look at the C standard for guidance on this.

Um, what is it that compiler writers and thread library writers
understand volatile to mean?
In the C11 parlance, what you're trying to write requires the "weak"
atomics, such as relaxed, acquire, release, and consume memory
operations. Attempting to write stuff like this without C11 support
with the C11 primitives is a wholly platform specific affair, and
neither C89 nor C90 can help you there. volatile specifically cannot
help you (barring platform specific documentation to the contrary).

You seem to be making too many assumptions about my code.
From else-thread:


That's your problem. You have broken code. Your options are:
1- broken code (e.g. using volatile and asm memory barriers absent
platform specific guarantees)
2- code that relies on platform specific guarantees (e.g. with using
volatile and asm memory barriers)
3- "slow" code (e.g. with posix mutexes)
4- C11 code

How do you know, a priori, that my code is broken? Do I have to
change my passwords again?


Regards,

Uncle Steve
 
U

Uncle Steve

I think it's pretty clear from what you've written else-thread.


How do I know it's broken? By your own admission, you're using
volatile to try and affect inter-thread visibility (absent constructs
that actually give inter-thread visibility). By your previous
statements about using the C standard to derive useful threading
semantics for volatile, I doubt you've looked at the compiler
documentation and hardware documentation for your implementation. Thus
you have broken code. (I don't think you are trying to nit on "it
could be right by coincidence".)

Well you know what? You're going to have to wait until version 1.0
before you get to decide how wrong it is.


Regards,

Uncle Steve
 
I

Ian Collins

08 AM, Uncle Steve wrote:
[...]
This is a concern in my mind right now as I'm writing some posix
threads code, and so obviously there are a large number of variables
which ought to be declared volatile.

What leads you to that conclusion? That line of though usually implies
you are misunderstanding the relationship between volatile and threads.

What are you trying to achieve with volatile?

Well, I have some data structures that will be accessed from arbitrary
threads, so I want to make sure there's no funny business happening
behind the scenes where the compiler decides that certain accesses are
optional.

Although the latest "C11" Standard adds some multi-threading
support, I'll ignore that because (1) C11 implementations are not
exactly thick upon the ground as yet, (2) you mentioned you're
using Pthreads anyhow, and (3) I haven't studied the C11 threading
stuff closely enough to be a competent commentator. ;-)

So: As long as you're using an established non-C-specific
threading framework, I suggest you visit comp.programming.threads,
a newsgroup devoted to multi-threading issues. There you will learn
that `volatile' is neither necessary *nor* sufficient in connection
with variables shared between threads. (You needn't take my word on
this: Just browse the comp.programming.threads archives and you'll
see the local experts refuting this misunderstanding every couple
weeks. It's comp.programming.threads' equivalent of `void main'.)

Or, as my first threading teacher put it, "Don't Do That."

Is there are C standard threading framework?

Yes, read C11. If you are familiar with pthreads, you'll see where most
of the new primitives originate.
Threaded code is a de-facto reality in today's multi-core environment.
Save for the embedded sector, most systems will run threads in
parallel, and that is that.

Only if you incorporate threads in your code either explicitly or
implicitly with something like OpenMP.
C has to recognize this watershed moment
in the refinement of the language.

It has.
While the specifics of an implementation within a given operating
system are not C issues, certain common optimizations can be a problem
with certain algorithms, and so there ought to be a C solution to the
problem. What is it about the volatile attribute that makes it
insufficient in your mind to the problem presented by threaded code?

Given you are the one going against conventional wisdom, what in your
mind makes volatile a solution to the problem presented by threaded code?

In addition, what is "the problem presented by threaded code"?
 
U

Uncle Steve

Let me share with you a story. I currently work for a company selling
Enterprise software. The software is heavily intertwined with
databases. We have a license for a large piece of code that does heavy
duty sorting. We have a contract with the guys who wrote this sorting
library for support and maintenance. One of our customers upgraded
some of their hardware, ran some tests - or possibly worse ran actual
usage - and noticed that one row out of a few billion was "missing".
Our engine dropped it, somewhere. It should be in the output, but it
wasn't. Of course, this is very bad for our company. This could cost
millions of dollars in sales. So, we get the guys who wrote the
sorting library, and immediately fly them out to us. We get them to
work on the code. I was only tangentially related to this process. It
took a week or so of work to find and fix the issue. What was the
problem? The guys who wrote the sorting library used "volatile", and
the customer just upgraded to some itanium processor or something. A
quick fix/hack later, and our customer was back in business, our
millions of dollars was secure, as was our company image and
reputation.

Use volatile at your own risk. I don't plan on using your software if
I can help it.

Well I wouldn't want you to use any software that you didn't want to
run.


Regards,

Uncle Steve
 
U

Uncle Steve

In other words, correctness would incur a performance penalty in
comparison to your synchronization primitives in some circumstances.

You probably shouldn't be using google translate to massage my code
into something you can understand. It doesn't work like that.
If I could parse that, I'd respond to it.

Yeah well it happens.
You aren't making much sense.

An example of you your synchronization primitives would clear things up.

Sorry, you're going to have to wait.


Regards,

Uncle Steve
 
J

Joshua Maurice

What leads you to that conclusion?  That line of though usually implies
you are misunderstanding the relationship between volatile and threads.
What are you trying to achieve with volatile?

Well, I have some data structures that will be accessed from arbitrary
threads, so I want to make sure there's no funny business happening
behind the scenes where the compiler decides that certain accesses are
optional.

[snip]

The variable declared volatile are required otherwise some variable
accesses are optimized out, giving inaccurate results during the data
acquisition phase.  The problems here are magnified when these access
patterns occur with competing threads.  IIRC, mutexes are not memory
access barriers and solve different problems.

To be topical, here's the answer for C11: volatile is useless as a
portable threading construct. Do not use it. It's (maybe) useful in a
portable way only for 3 obscure situations: MMIO, setjmp and longjmp
stuff, and signal handling. If you properly use C11 mutexes, there is
absolutely no need for volatile. To paraphrase you else-thread, there
will be no "funny business" if you use mutexes correctly. It tells the
compiler, the hardware, and anything else relevant, to obey the
semantics of the mutex. volatile is similarly useless when you
correctly use the new "weak" C11 atomics. volatile adds nothing
(portably).

Now, to finally answer your question, C11 threading semantics,
including the lack of useful volatile semantics, is basically copied
wholesale from pthreads. Don't use volatile as a portable threading
construct with pthreads either. pthread mutexes do everything you
need. volatile adds absolutely nothing (portably).

(Yes, you can accomplish useful code with volatile for specific
platform and specific compilers with specific settings. That's an
"advanced" topic that I won't cover now.)

Now, what do you mean by "mutexes are not memory access barriers"?
Mutexes do two things: they provide blocking semantics for mutual
exclusion, and they guarantee visibility ala the usual "happens-
before" semantics. Mutexes are implemented with hardware memory
fences / barriers. This is all true for mutexes in pthreads, win32
threads, Boost threads, ACE threads, C11 threads, C++11 threads, and
every case I can recall seeing the word "mutex".
 
T

Tim Rentsch

Ben Bacarisse said:
[can optimization sometimes be done even though volatile is used?]

To a very large extent, the C standard washes it hands of volatile
objects. Sure, it says a fair bit about what *may* happen but it also
says "[w]hat constitutes an access to an object that has volatile-
qualified type is implementation-defined" (6.7.3 p7) and "[a]n actual
implementation need not evaluate part of an expression if it can deduce
that [...] no needed side effects are produced (including any caused by
[...] accessing a volatile object)" (5.1.2.3 p4).

Together, these give an implementation so much leeway that you often
need to refer to the implementation, not the standard. For example, an
implementation may well be able to deduce that the assignment is not a
"needed side effect", coming as it does at the start of main. Equally,
an implementation may treat all accesses to volatile-qualified objects
with kid gloves.

My conclusion is similar to yours, but we're 180 degrees
apart on the reading of 5.1.2.3 p4. Any access to a
volatile object potentially causes a needed side-effect, and
there is -- by definition -- _no way_ for an implementation
to know whether or which accesses to volatile objects will
cause such a side-effect. However an implementation chooses
to define what actions constitute an access to a volatile
object, these actions _must_ be carried out for each such
access that is evaluated during a program execution, whether
it seems to have any bearing on other "needed" side-effects
or not. All the latitude comes from 6.7.3 p7; none comes
from 5.1.2.3 p4, and in fact just the opposite. Such
actions must in fact be carried out during actual execution,
and must not be "optimized away" no matter whether they seem
to have any bearing on other program behavior or not.

Anyway that's my reading/interpretation; I don't mean to
start any arguments about which reading is right, but I
thought you would want to know that they are different.
 
I

Ian Collins

Well, I don't follow gcc development, so I don't know when those
features will be available on my system.

Then use your platform's native threading primitives.
Well, sure, but I'd like to think that multithreaded applications will
be popular. It helps to improve the interactivity of applications
with a GUI frontend for one thing, never mind what you can do with
message-passing interfaces or asynchronus network I/O threads.

There already are.
O.K., so do nested structure elements inherit the parent structure's
volatile attribute?

A volatile T is a volatile T no matter what it contains.
Well, code optimization from global CSE might eliminate memory
accesses to variable that could be modified by other threads in ways
that affect the algorithm. Depends of the code.

If the code depends on volatile, it is broken. Use the atomics or
synchronisation primitives provided by the language or platform. They
exist for a reason.
 
B

Ben Bacarisse

Tim Rentsch said:
Ben Bacarisse said:
[can optimization sometimes be done even though volatile is used?]

To a very large extent, the C standard washes it hands of volatile
objects. Sure, it says a fair bit about what *may* happen but it also
says "[w]hat constitutes an access to an object that has volatile-
qualified type is implementation-defined" (6.7.3 p7) and "[a]n actual
implementation need not evaluate part of an expression if it can deduce
that [...] no needed side effects are produced (including any caused by
[...] accessing a volatile object)" (5.1.2.3 p4).

Together, these give an implementation so much leeway that you often
need to refer to the implementation, not the standard. For example, an
implementation may well be able to deduce that the assignment is not a
"needed side effect", coming as it does at the start of main. Equally,
an implementation may treat all accesses to volatile-qualified objects
with kid gloves.

My conclusion is similar to yours, but we're 180 degrees
apart on the reading of 5.1.2.3 p4. Any access to a
volatile object potentially causes a needed side-effect, and
there is -- by definition -- _no way_ for an implementation
to know whether or which accesses to volatile objects will
cause such a side-effect. However an implementation chooses
to define what actions constitute an access to a volatile
object, these actions _must_ be carried out for each such
access that is evaluated during a program execution, whether
it seems to have any bearing on other "needed" side-effects
or not. All the latitude comes from 6.7.3 p7; none comes
from 5.1.2.3 p4, and in fact just the opposite. Such
actions must in fact be carried out during actual execution,
and must not be "optimized away" no matter whether they seem
to have any bearing on other program behavior or not.

Anyway that's my reading/interpretation; I don't mean to
start any arguments about which reading is right, but I
thought you would want to know that they are different.

OK, I can see that. I.e. is there permission to deduce that the side
effect is needed or simply to deduce that it is produced? I will pin my
colours firmly to fence I am sitting on and say hmmm...
 
J

Joshua Maurice

Well, mutexes are barriers for the memory accesses associated with the
mutex itself, but not in general.  Reading the above I can tell that
you think I'm using POSIX mutexes, however that is not the case.

I strongly suggest that you don't use the word "mutex" for your code
because you will confuse most readers. Most readers will associate
"mutex" with both mutual exclusion and "happens-before" global memory
visibility. That's how the term has been commonly used (ex: posix
pthreads), and how it will continue to commonly be used (ex: C11).
 I am
using a custom locking scheme that allows for concurrent readers, but
is exclusive for writers.  As a consequence, the behavior of
variables marked volatile in my code is critical, so I don't want to
mistakenly use it in a way that results in surprises.

Now you can say that what I am doing is non-portable, but you would
be wrong there since my algorithms are in fact portable as long as I
am following the rules of the C standard.  Perhaps the proper term is
limited portability as I rely on a tiny amount of platform specific
asm.  (One instruction.)

I will say it again: the C89 and C99 standards do not mean what you
think. What the compiler writers and thread library writers understand
volatile to mean is not what you understand volatile to mean, and at
the end of the day what the compiler writers and thread library
writers think is paramount. You may be able to get this to work for
specific platforms with specific compilers. I suggest you ask in a
location specific to such implementations for such platform specific
hackery. However, do not look at the C standard for guidance on this.

In the C11 parlance, what you're trying to write requires the "weak"
atomics, such as relaxed, acquire, release, and consume memory
operations. Attempting to write stuff like this without C11 support
with the C11 primitives is a wholly platform specific affair, and
neither C89 nor C90 can help you there. volatile specifically cannot
help you (barring platform specific documentation to the contrary).

From else-thread:
Doing so would incur a performance penalty in comparison to my
synchronization primitives in some circumstances.

That's your problem. You have broken code. Your options are:
1- broken code (e.g. using volatile and asm memory barriers absent
platform specific guarantees)
2- code that relies on platform specific guarantees (e.g. with using
volatile and asm memory barriers)
3- "slow" code (e.g. with posix mutexes)
4- C11 code
 

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

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top