How to enforce execution order?

  • Thread starter =?ISO-8859-1?Q?Sacha_Sch=E4r?=
  • Start date
?

=?ISO-8859-1?Q?Sacha_Sch=E4r?=

Hi there,

i have a sequence like the following:

const char *a = "foo";
char b[10];

for ( i = 1; i < strlen(a); i++)
{
b = a;
}
b[0] = a[0];

I guess, an optimizing compiler might mixup the execution order of this
code snipped. How can I enforce, that the copying of the char at
position 0 is done after the loop?

I work in a multithreaded environment, and Semaphores, Mutex etc. are
not suitable for the current situation.

-Sacha

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
M

Mike Wahler

Sacha Schär said:
Hi there,

i have a sequence like the following:

const char *a = "foo";
char b[10];

for ( i = 1; i < strlen(a); i++)
{
b = a;
}
b[0] = a[0];

I guess, an optimizing compiler might mixup the execution order of this
code snipped. How can I enforce, that the copying of the char at
position 0 is done after the loop?


volatile const char *a = "foo";

BTW why are you using C-style strings instead of std::string?


-Mike
 
V

Victor Bazarov

Sacha said:
i have a sequence like the following:

const char *a = "foo";
char b[10];

for ( i = 1; i < strlen(a); i++)
{
b = a;
}
b[0] = a[0];

I guess, an optimizing compiler might mixup the execution order of this
code snipped. How can I enforce, that the copying of the char at
position 0 is done after the loop?


Turn off optimizations for this particular piece of code. Consult with
your compiler manual on how to do that.
I work in a multithreaded environment, and Semaphores, Mutex etc. are
not suitable for the current situation.

And it's not relevant to the newsgroups you posted to, anyway. There are
no such things like "Semaphores" or "Mutex" in C++.

V
 
J

Joshua Zimler

This is just a guess.. how about an inline function?

void inline copyFirstElem(const char *a, char *b)
{
b[0] = a[0]
}

{Please do not top post. -mod/fg}
Hi there,

i have a sequence like the following:

const char *a = "foo";
char b[10];

for ( i = 1; i < strlen(a); i++)
{
b = a;
}
b[0] = a[0];

I guess, an optimizing compiler might mixup the execution order of this
code snipped. How can I enforce, that the copying of the char at
position 0 is done after the loop?

I work in a multithreaded environment, and Semaphores, Mutex etc. are
not suitable for the current situation.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
?

=?ISO-8859-15?Q?Andr=E9_Kempe?=

Sacha Schär schrieb:
for ( i = 1; i < strlen(a); i++)
{
b = a;
}
b[0] = a[0];

I guess, an optimizing compiler might mixup the execution order of this
code snipped. How can I enforce, that the copying of the char at
position 0 is done after the loop?


switch off all optimizations?

to be honest, you'd have to fool the compiler's optimization by using
some value that could be computed only at the end of the loop i.e.

int i;
for ( i = 0 ; i < strlen(a); i++ )
{ b = a; }

// this is not portable at the moment
// i think there is a macro CHAR_BYTES that should replace the "8"
// and the mask must be fixed
b[0] = ((unsigned int)i<<8|(unsigned int)(a[0]))&0xff;

however, even with this the compiler might be clever enough to get it out.

the most secure way would be to reimplement the loop using assembler.

greetings from dresden
andré

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
M

Maciej Sobczak

Sacha said:
i have a sequence like the following:

const char *a = "foo";
char b[10];

for ( i = 1; i < strlen(a); i++)
{
b = a;
}
b[0] = a[0];

I guess, an optimizing compiler might mixup the execution order of this
code snipped.


Sure, it can do whatever it wants, as far as the final effect is the same.
How can I enforce, that the copying of the char at
position 0 is done after the loop?

It does not make any difference. After all, you want to copy some bytes
somewhere, right?
I work in a multithreaded environment

So you don't want to *just* copy some bytes somewhere, you want to make
some more complicated logic on top of it.
If a and b are shared objects, then you have to use proper tools to make
the threads properly collaborate. It's not only about order, but also
about visibility.
and Semaphores, Mutex etc. are
not suitable for the current situation.

Why? Without proper synchronization tools, there is nothing you can do
to *enforce* any particular ordering of events in the multithreaded
application.


--
Maciej Sobczak : http://www.msobczak.com/
Programming : http://www.msobczak.com/prog/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
K

kanze

Sacha said:
i have a sequence like the following:
const char *a = "foo";
char b[10];
for ( i = 1; i < strlen(a); i++)
{
b = a;
}
b[0] = a[0];

I guess, an optimizing compiler might mixup the execution
order of this code snipped. How can I enforce, that the
copying of the char at position 0 is done after the loop?

In what sense? The standard requires that the observable
behavior be as if the assignment at position 0 occured after the
loop. But since there is no observable behavior in the above, a
compiler can pretty much do what it wants. Because there is no
observable behavior, of course, you can't tell what it does,
either.
I work in a multithreaded environment, and Semaphores, Mutex
etc. are not suitable for the current situation.

If other threads can access b, then you cannot avoid some sort
of synchronization primitive. Posix offers mutex, and a few
others; Windows, and many Unix platforms, also have lower level
primitives. But without some primitive, there is no guarantee
concerning the order of the writes as seen in another thread.
(And it's not just a problem of the compiler. Modern hardware
does considerable reordering itself. The primitives will use
special hardware instructions to inhibit the reordering. And
typically, there is no way to get the compiler to emit these
instructions; it must be done in assembler.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
N

Niklas Matthies

i have a sequence like the following:

const char *a = "foo";
char b[10];

for ( i = 1; i < strlen(a); i++)
{
b = a;
}
b[0] = a[0];

I guess, an optimizing compiler might mixup the execution order of this
code snipped. How can I enforce, that the copying of the char at
position 0 is done after the loop?

I work in a multithreaded environment, and Semaphores, Mutex etc. are
not suitable for the current situation.


The reordering of accesses by the compiler can be prevented by
performing the relevant accesses through volatile-qualified lvalues.
But in a multithreaded environment this isn't good enough, because the
hardware can reorder accesses as well, in addition to the compiler.
To prevent such reordering at the hardware level, you need to issue
a memory barrier instruction, either directly or by employing some
synchronization primitive. How you can do this is compiler- and/or
OS-dependent.

-- Niklas Matthies

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
A

Allan W

Sacha said:
I guess, an optimizing compiler might mixup the execution order of this
code snipped. How can I enforce, that the copying of the char at
position 0 is done after the loop?

Put it in an _asm block.
Or put an empty _asm block between the loop and the last line.
Or turn off optimization.

Or, document the problem and report it to the compiler...
if you can tell the difference in a conforming program, then the
compiler is broken.
I work in a multithreaded environment, and Semaphores, Mutex etc. are
not suitable for the current situation.

In a multithreaded environment, strike the bit about a conforming
program,
because the standard doesn't currently address multiple threads.
But still, if the semaphore or whatever works properly, it ought to
guard the order of your program's execution.
Check your compiler's documentation!


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
B

Bo Persson

Sacha Schär said:
Hi there,

i have a sequence like the following:

const char *a = "foo";
char b[10];

for ( i = 1; i < strlen(a); i++)
{
b = a;
}
b[0] = a[0];

I guess, an optimizing compiler might mixup the execution order of
this
code snipped. How can I enforce, that the copying of the char at
position 0 is done after the loop?


Why would you?

An optimizing compiler can do anything it likes, as long as you can't
tell the difference. That is called the "as-if" rule. The code must be
executed as-if it is done exactly in the order you write it.

Can you tell the difference?


Bo Persson




[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
V

Valentin Samko

Sacha said:
const char *a = "foo";
char b[10];
for ( i = 1; i < strlen(a); i++)
b = a;
b[0] = a[0];

I guess, an optimizing compiler might mixup the execution order of this
code snipped.

Yes, as long as the observable behaviour does not change.
How can I enforce, that the copying of the char at
position 0 is done after the loop?
Make 'b' volatile "volatile char b[10]".
I work in a multithreaded environment, and Semaphores, Mutex etc. are
not suitable for the current situation.
You should also consider CPU cache coherency. For example, another thread may run on
another CPU and it's cache may contain different values in 'b' than the cache of the CPU
running your main thread. You may also need a memory barrier here.

It would help you you explained the problem you are trying to solve.

Also, it is not efficient to call strlen in each iteration, it would be a way faster to
calculate it once and use that value (although sometimes a good compiler may be able to
optimise that call away if it can prove that 'a' and 'b' do not overlap).

--

Valentin Samko - http://www.valentinsamko.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
C

Catalin Marinas

Sacha Schär said:
i have a sequence like the following:

const char *a = "foo";
char b[10];

for ( i = 1; i < strlen(a); i++)
{
b = a;
}
b[0] = a[0];

I guess, an optimizing compiler might mixup the execution order of this
code snipped. How can I enforce, that the copying of the char at
position 0 is done after the loop?


Why do you need this? It might not be enough to ensure that "b[0] =
a[0]" happens at the end since the compiler might not even write the
data to memory but keep it in registers up to a point.

You can use a compiler barrier before the last assignment (and maybe
one more after it if you want to ensure that the data was really
written to memory). In general, any function call (which is not
inlined) is a compiler barrier. Otherwise, it depends on the
compiler. For gcc, an empty asm directive would do the job:

asm volatile ("" : : : "memory");

It might help if you detail the problem you are seeing a bit more.
 
K

kanze

André Kempe said:
Sacha Schär schrieb:
for ( i = 1; i < strlen(a); i++)
{
b = a;
}
b[0] = a[0];
I guess, an optimizing compiler might mixup the execution
order of this code snipped. How can I enforce, that the
copying of the char at position 0 is done after the loop?

switch off all optimizations?

[...]
the most secure way would be to reimplement the loop using
assembler.

Note that even then, unless you use special instructions to
ensure otherwise, another thread may see the writes in a
different order.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
K

kanze

Catalin said:
Sacha Schär said:
i have a sequence like the following:
const char *a = "foo";
char b[10];
for ( i = 1; i < strlen(a); i++)
{
b = a;
}
b[0] = a[0];
I guess, an optimizing compiler might mixup the execution
order of this code snipped. How can I enforce, that the
copying of the char at position 0 is done after the loop?

Why do you need this? It might not be enough to ensure that
"b[0] = a[0]" happens at the end since the compiler might not
even write the data to memory but keep it in registers up to a
point.
You can use a compiler barrier before the last assignment (and
maybe one more after it if you want to ensure that the data
was really written to memory). In general, any function call
(which is not inlined) is a compiler barrier. Otherwise, it
depends on the compiler. For gcc, an empty asm directive would
do the job:
asm volatile ("" : : : "memory");

Not on a Sparc. You'd have to put a membar instruction in the
asm directive.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
C

Catalin Marinas

kanze said:
Not on a Sparc. You'd have to put a membar instruction in the
asm directive.

I was only talking about the compiler barrier, not the hardware
one. If you are not on an SMP system or the memory location doesn't
need to be accessed by something other than the CPU itself, an empty
asm instruction is enough. This is because even if the value didn't
get to memory (weakly ordered memory or write buffers), the CPU should
be smart enough to get it from the write buffers if it is read by
itself. The only use of this is probably for the code that breaks the
strict aliasing rules.

On SMP or if the location is shared with a device, indeed you would
need a hardware memory barrier as well (and maybe cache flushing). My
experience is mainly with ARM processors but I don't think it is too
different on Sparc (I might be wrong though).
 

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,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top