title: Benefits & drawbacks of as-needed conditional std::atomic_thread_fence acquire?
body: <p>The code below shows two ways of acquiring shared state via an atomic flag. The reader thread calls <code>poll1()</code> or <code>poll2()</code> to check for whether the writer has signaled the flag.</p>
  
  <p>Poll Option #1:</p>
  
  <pre><code>bool poll1() {
      return (flag.load(std::memory_order_acquire) == 1);
  }
  </code></pre>
  
  <p>Poll Option #2:</p>
  
  <pre><code>bool poll2() {
      int snapshot = flag.load(std::memory_order_relaxed);
      if (snapshot == 1) {
          std::atomic_thread_fence(std::memory_order_acquire);
          return true;
      }
      return false;
  }
  </code></pre>
  
  <p>Note that option #1 was <a href="https://stackoverflow.com/questions/35254171/can-stdatomic-memory-barriers-be-used-to-transfer-non-atomic-data-between-thre/35254379#35254379">presented in an earlier question</a>, and option #2 is  similar to <a href="http://en.cppreference.com/w/cpp/atomic/atomic_thread_fence" rel="nofollow noreferrer">example code at cppreference.com</a>.</p>
  
  <p>Assuming that the reader agrees to only examine the shared state if the <code>poll</code> function returns <code>true</code>, are the two <code>poll</code> functions both correct and equivalent?</p>
  
  <p>Does option #2 have a standard name?</p>
  
  <p>What are the benefits and drawbacks of each option? </p>
  
  <p>Is option #2 likely to be more efficient in practice? Is it possible for it to be less efficient?</p>
  
  <p>Here is a full working example:</p>
  
  <pre><code>#include &lt;atomic&gt;
  #include &lt;chrono&gt;
  #include &lt;iostream&gt;
  #include &lt;thread&gt;
  
  int x; // regular variable, could be a complex data structure
  
  std::atomic&lt;int&gt; flag { 0 };
  
  void writer_thread() {
      x = 42;
      // release value x to reader thread
      flag.store(1, std::memory_order_release);
  }
  
  bool poll1() {
      return (flag.load(std::memory_order_acquire) == 1);
  }
  
  bool poll2() {
      int snapshot = flag.load(std::memory_order_relaxed);
      if (snapshot == 1) {
          std::atomic_thread_fence(std::memory_order_acquire);
          return true;
      }
      return false;
  }
  
  int main() {
      x = 0;
  
      std::thread t(writer_thread);
  
      // "reader thread" ...  
      // sleep-wait is just for the test.
      // production code calls poll() at specific points
  
      while (!poll2()) // poll1() or poll2() here
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
  
      std::cout &lt;&lt; x &lt;&lt; std::endl;
  
      t.join();
  }
  </code></pre>