<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Jul 20, 2016 at 12:43 PM, Craig, Ben via cfe-dev <span dir="ltr"><<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
  

    
  
  <div bgcolor="#FFFFFF" text="#000000">
    <p>C++14 6.7 Declaration statement, clause 4 has the standardese for
      "Magic" / thread-safe statics.  Footnote 91 says "The
      implementation must not introduce any deadlock around execution of
      the initializer."  I believe this is unimplementable.</p></div></blockquote><div><br></div><div>While your interpretation is not unreasonable, I believe you've misunderstood the meaning and intent of this footnote. Note that it says *the implementation* must not introduce any deadlock -- that is, there must not be any deadlock that is not implied by the program semantics. The normative sentence preceding this footnote says "If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization." The potential for deadlock in that rule is not affected by the presence of this footnote, because that's deadlock introduced by the language semantics, not deadlock introduced by the implementation.</div><div><br></div><div>To understand the purpose of this footnote, you need to look at how GCC 3.x implemented thread-safe local statics (prior to standardization). They had a single, global, recursive mutex protecting all local static initialization. This results in deadlock *introduced by the implementation* if a static local variable's initializer spawns and joins a thread, and that thread triggers initialization of a different static local variable. It is specifically that implementation strategy which is being called out as non-conforming here.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div bgcolor="#FFFFFF" text="#000000"><p>The
      standard (and users) require mutual exclusion (though not
      necessarily a mutex) to be provided over unknown / arbitrary
      code.  This causes well known problems (
<a href="http://www.drdobbs.com/cpp/avoid-calling-unknown-code-while-inside/202802983" target="_blank">http://www.drdobbs.com/cpp/avoid-calling-unknown-code-while-inside/202802983</a>
      ).<br>
    </p>
    <p>Libcxxabi, libsupc++, and the Microsoft implementation all have
      deadlocks in released compilers.  I have two examples, one heavily
      contrived, and the other lightly contrived.<br>
    </p>
    <b>Heavily contrived example:<br>
    </b>In the following code, the static A2 can cause the static B2 to
    be constructed, and B2 can cause the static A2 to be constructed.  A
    bool is passed along to prevent recursion.  This leads to the
    classic "deadly embrace", where each thread is waiting for a
    resource from the other thread to be released.  The sleeps have been
    added to make the race condition more likely to trigger.  No user
    data is racing in this example.  There would be a hidden data race
    on the "is initialized" flag on each of the statics, except that
    that is one of the races that thread-safe statics is supposed to
    fix.<br>
    <br>
    <tt>#include <thread></tt><tt><br>
    </tt><tt><br>
    </tt><tt>using namespace std::chrono_literals;</tt><tt><br>
    </tt><tt><br>
    </tt><tt>void aMaker(bool MakeB);</tt><tt><br>
    </tt><tt>void bMaker(bool MakeA);</tt><tt><br>
    </tt><tt><br>
    </tt><tt>struct SlowA {</tt><tt><br>
    </tt><tt>  explicit SlowA(bool MakeB) {</tt><tt><br>
    </tt><tt>    std::this_thread::sleep_for(2s);</tt><tt><br>
    </tt><tt>    if(MakeB) bMaker(false);</tt><tt><br>
    </tt><tt>  }</tt><tt><br>
    </tt><tt>};</tt><tt><br>
    </tt><tt><br>
    </tt><tt>struct FastB {</tt><tt><br>
    </tt><tt>  explicit FastB(bool MakeA) {</tt><tt><br>
    </tt><tt>    if(MakeA) aMaker(false);</tt><tt><br>
    </tt><tt>  }</tt><tt><br>
    </tt><tt>};</tt><tt><br>
    </tt><tt><br>
    </tt><tt>void aMaker(bool MakeB) {  static SlowA A2(MakeB); };</tt><tt><br>
    </tt><tt>void bMaker(bool MakeA) {  static FastB B2(MakeA); };</tt><tt><br>
    </tt><tt><br>
    </tt><tt>int main() {</tt><tt><br>
    </tt><tt>  std::thread first( []{aMaker(true);});</tt><tt><br>
    </tt><tt>  std::this_thread::sleep_for(1s);</tt><tt><br>
    </tt><tt>  std::thread second([]{bMaker(true);});</tt><tt><br>
    </tt><tt>  </tt><tt><br>
    </tt><tt>  first.join();</tt><tt><br>
    </tt><tt>  second.join();</tt><tt><br>
    </tt><tt>}</tt><br>
    <br>
    <b>Lightly contrived example:<br>
    </b>In the following code, we cause a deadlock with only one user
    defined recursive mutex.  I think this issue could actually affect
    real code bases, though I haven't hit the problem myself.<br>
    <br>
    <tt>#include <thread><br>
      #include <mutex><br>
      <br>
      std::recursive_mutex g_mutex;<br>
      <br>
      struct SlowA {<br>
        explicit SlowA() {<br>
          std::lock_guard<std::recursive_mutex> guard(g_mutex);<br>
        }<br>
      };<br>
      <br>
      void aMaker() {<br>
        static SlowA A2;<br>
      };<br>
      <br>
      int main() {<br>
        using namespace std::chrono_literals;<br>
        std::thread first([]{<br>
          std::lock_guard<std::recursive_mutex> guard(g_mutex);<br>
          std::this_thread::sleep_for(2s);<br>
          aMaker();<br>
        });<br>
        std::this_thread::sleep_for(1s);<br>
        std::thread second([]{ aMaker(); });<br>
      <br>
        first.join();<br>
        second.join();<br>
      }<br>
    </tt><br>
    <br>
    I'm not sure what should be done.  Removing the lock protections
    would be terrible.  Banning the use of locks in functions that
    construct statics would be terrible.  Banning the use of locks in
    functions called from static construction would be terrible.  It
    would be embarrassing to change the footnote in the standard to say
    that the language is permitted (even required) to introduce
    deadlocks.<span class=""><font color="#888888"><br>
    <pre cols="72">-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
</pre>
  </font></span></div>

<br>_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
<br></blockquote></div><br></div></div>