Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiler Optimization, Thread Safe?

I have a question regarding optimizations the compiler can potentially do.

The below code will speak for itself (this is an example):

typedef struct  test
{
  short i;
}               s_test;

int function1(char *bin)
{
  s_test foo;

  lock(gmutex);
  foo.i = *(int*)bin * 8;
  unlock(gmutex);

  sleep(5);
  //
  // Here anything can happen to *bin in another thread
  // an inline example here could be: *(volatile int *)bin = 42;
  //

  int b = foo.i + sizeof(char*);

  return (b > 1000);
}

Could the compiler ever replace the last lines with

return ((*(int*)bin * 8 + sizeof(char*)) > 1000);

It did not seem to be the case using -O2 or -O3 with gcc 4.4 but could it be the case with other compilers and with other compilation flags?

like image 638
Dpp Avatar asked Jun 05 '12 07:06

Dpp


3 Answers

I don't think compiler will do such kind of optimization.

unlock(gmutex)

this is function, the compiler can't assume that value pointed by bin will be changed in unlock function or not.

for example, maybe bin comes from a globe. So optimization for bin can't cross the function call.

like image 90
RolandXu Avatar answered Sep 28 '22 02:09

RolandXu


Your example is unnecessarily complicated because you are reading bin through a different type than it is declared. Aliasing rules are quite complicated, char is even special, I wouldn't comment on that.

Supposing your declaration would be int* bin (and so you wouldn't have to cast the pointer) a compiler would not have the right to reorder statements across function calls, they form so-called sequence points. The value of *bin before and after the call to unlock could be different, so it has to load the value after the call.

Edit: as noted by slartibartfast, for this argument it is essential that unlock is (or contains) a function call and isn't just a macro that resolves to a sequence of operations by the compiler.

like image 23
Jens Gustedt Avatar answered Sep 28 '22 01:09

Jens Gustedt


As I said in the direct reply: your mutex isn't protecting anything IMHO. The char array which *bin points into can get modified during the int-access so depending on your machine you won't even get a consistent view on the memory you wanted to access. Back to your question: a compiler will not transform the source code to the sequence which you envisioned BUT it may very well produce machine language which in effect will behave the way your source code does. If it is able to inspect the functions lock, unlock and sleep (which seem to be macros anyway) and can deduce that there is no side effect to the involved memory locations AND there is no implementation defined meaning to calls to e.g. sleep() which would render temporary ("cached" although the standard doesn't use this term) values invalid then it is entitled to produce an instruction sequence like the one you gave. C (up to C99) is inherently single-threaded and the compiler can employ any optimization strategy it wants as long as the code behaves "as if" it would run on the ideal hypothetical C machine. The sequence points which Jens mentioned don't affect the correctness under single threaded conditions: the compiler could hold foo in a register during the whole function or it could even alias foo.i with the memory location pointed to by *bin, so this code is inherently dangerous (alhtough I think it will not exhibit this behaviour on most compilers).

like image 36
slartibartfast Avatar answered Sep 28 '22 01:09

slartibartfast