Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Forgive me my ignorance, but if I write

  int foo(int *x) {
    *x = 0;
    // wait until another thread writes to *x
    return *x;
  }

Can the C compiler really optimize foo to always return 0? That seems extremely unintuitive to me.


How do you accomplish the waiting operation? If it does not synchronize with the other thread, the compiler will optimize away the load. This isn't too surprising once you assume that not every *x in the source code will result in a memory access instruction. I would even say that most C programmers expect such basic optimizations to happen, although they might not always like the consequences.


> Can the C compiler really optimize foo to always return 0?

Yes

> That seems extremely unintuitive to me.

C compilers are extremely unintuitive. This is a relatively sane case, they do things that are much more surprising than this.


In a multithreaded, hosted userspace program the wait operations should synchronize with another thread. This involves inserting optimization barriers that are understood by the compiler, therefore it can't optimize the this case to always return 0.


In embedded this situation is quite common when x points to a hardware register. The typical solution is to declare x as volatile[1] which tells the compiler to omit these optimizations.

It's very common for beginner embedded programmers to forget to do this and spend hours debugging why the register doesn't change when it should.

[1] https://en.m.wikipedia.org/wiki/Volatile_(computer_programmi...


No, because in practice that "wait until" operation will act as a memory barrier. The obvious one is a function call. Functions are allowed to have side effects, one possible side effect is to change the value pointed to by an externally-received pointer.

At lower levels, you might have something like an IPC primitive there, which would be protected by a spinlock or similar abstraction, the inline assembly for which will include a memory barrier.

And even farther down still, the memory pointed to by "x" might be shared with another async context entirely and the "wait for" operation might be a delay loop waiting on external hardware to complete. In that case this code would be buggy and you should have declared the data volatile.


> No, because in practice that "wait until" operation will act as a memory barrier.

This is a wrong, a memory barrier would not salvage this code from UB. The read from `x` must at the very least be synchronized, and there might be other UB lurking as well.


No, synchronization is a different issue entirely. The question upthread was whether it was OK for the compiler to optimize the code to return a constant zero without actually reading from the pointer. And it's not, because any reasonable implementation of "wait for" will defeat aliasing analysis.

You're right that if you try to write async code with only compiler instrumentation, you're very likely to be introducing race conditions (to be clear: not necessarily on architectures with sufficiently clear memory ordering behavior -- you can play tricks like this in pure C with x86 for instance). But that wasn't the question at hand.


That's the most straight-forward example of undefined behavior badness you'll find. Things on practice are usually way less intuitive than this (mostly because people notice and avoid writing those straight-forward problems).


Yes. You'd have to use

  int volatile *x
as the parameter to get the changes from a different thread.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: