title: Do sequence points prevent code reordering across critical section boundaries?
body: <p>Suppose that one has some lock based code like the following where mutexes are used to guard against inappropriate concurrent read and write</p>
  
  <pre><code>mutex.get() ; // get a lock.
  
  T localVar = pSharedMem-&gt;v ; // read something
  pSharedMem-&gt;w = blah ; // write something.
  pSharedMem-&gt;z++ ;      // read and write something.
  
  mutex.release() ; // release the lock.
  </code></pre>
  
  <p>If one assumed that the generated code was created in program order, there is still a requirement for appropriate <em>hardware</em> memory barriers like isync,lwsync,.acq,.rel.  I'll assume for this question that the mutex implementation takes care of this part, providing a guarentee that the pSharedMem reads and writes all occur "after" the get, and "before" the release() [but that surrounding reads and writes can get into the critical section as I expect is the norm for mutex implementations].  I'll also assume that volatile accesses are used in the mutex implementation where appropriate, but that volatile is NOT used for the data protected by the mutex (understanding why volatile does not appear to be a requirement for the mutex protected Data is really part of this question).</p>
  
  <p>I'd like to understand what prevents the <em>compiler</em> from moving the pSharedMem accesses outside of the critical region.  In the C and C++ standards I see that there is a concept of sequence point.  Much of the sequence point text in the standards docs I found incomprehensible, but if I was to guess what it was about, it is a statement that code should not be reordered across a point where there is a call with unknown side effects.  Is that the jist of it?  If that is the case what sort of optimization freedom does the compiler have here?</p>
  
  <p>With compilers doing tricky optimizations like profile driven interprocedural inlining (even across file boundaries), even the concept of unknown side effect gets kind of blurry.</p>
  
  <p>It is perhaps beyond the scope of a simple question to explain this in a self contained way here, so I am open to being pointed at references (preferrably online and targetted at mortal programmers not compiler writers and language designers).</p>
  
  <p>EDIT: (in response to Jalf's reply)</p>
  
  <p>I'd mentioned the memory barrier instructions like lwsync and isync because of the CPU reordering issues you also mentioned.  I happen to work in the same lab as the compiler guys (for one of our platforms at least), and having talked to the implementers of the intrinsics I happen to know that at least for the xlC compiler __isync() and __lwsync() (and the rest of the atomic intrinsics) are also a code reordering barrier.  In our spinlock implementation this is visible to the compiler since this part of our critical section is inlined.</p>
  
  <p>However, suppose you weren't using a custom build lock implementation (like we happen to be, which is likely uncommon), and just called a generic interface such as pthread_mutex_lock().  There the compiler isn't informed anything more than the prototype.  I've never seen it suggested that code would be non-functional </p>
  
  <pre>
  pthread_mutex_lock( &m ) ;
  pSharedMem->someNonVolatileVar++ ;
  pthread_mutex_unlock( &m ) ;
  
  pthread_mutex_lock( &m ) ;
  pSharedMem->someNonVolatileVar++ ;
  pthread_mutex_unlock( &m ) ;
  </pre>
  
  <p>would be non-functional unless the variable was changed to volatile.  That increment is going to have a load/increment/store sequence in each of the back to back blocks of code, and would not operate correctly if the value of the first increment is retained in-register for the second.</p>
  
  <p>It seems likely that the unknown side effects of the pthread_mutex_lock() is what protects this back to back increment example from behaving incorrectly.</p>
  
  <p>I'm talking myself into a conclusion that the semantics of a code sequence like this in a threaded environment is not really strictly covered by the C or C++ language specs.</p>