Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>tl;dr:</strong><br> The factory call could well take several steps that may be moved after the assignment to <code>m_pValue</code>. The expression <code>!m_pValue</code> would return false before the factory call is complete, giving an incomplete return value in the second thread.</p> <p><strong>Explanation:</strong></p> <blockquote> <p>Compiles probably omit writing to pValue, but never optimize such that moving assignment before the function call, otherwise it would violate the program semantics. </p> </blockquote> <p>Not necessarily. Consider T to be <code>int*</code>, and the factory method creates a new int and initializes it with 42.</p> <pre><code>int* pValue = new int(42); m_pValue = pValue; //m_pValue now points to anewly allocated int with value 42. </code></pre> <p>For the compiler the <code>new</code> expression would be several steps that could be moved before another. It's semantics are allocation, initialization, and then assignment of the address to <code>pValue</code>:</p> <pre><code>int* pTmp = new int; *pTmp = 42; int* pValue = *pTmp; </code></pre> <p>In a sequential program, the semantics would not change if some of the commands are moved after others. Especially the assignment can be moved freely between the memory allocation and the first access, i.e. the first dereferencing of one of the pointers, including after the assignment of the pointer values after the new expression:</p> <pre><code>int* pTmp = new int; int* pValue = *pTmp; m_pValue = pValue; *pTmp = 42; //m_pValue now points to a newly allocated int with value 42. </code></pre> <p>The compiler will probably do that to optimize most of the temporary pointers away:</p> <pre><code>m_pValue = new int; *m_pValue = 42; //m_pValue now points to a newly allocated int with value 42. </code></pre> <p>This is correct semantics for a <em>sequential</em> program.</p> <blockquote> <p>I believe LeaveCriticalSection has implicit hardware fence. And hence any writing before assignment to m_pValue will be synchronized.</p> </blockquote> <p>No. The fence is after the assignment to m_pValue, but the compiler can still move the integer assignment between that and the fence:</p> <pre><code>m_pValue = new int; *m_pValue = 42; LeaveCriticalSection(); </code></pre> <p>And that's too late, because Thread2 does not need to enter the CriticalSection:</p> <pre><code>Thread 1: | Thread 2: | m_pValue = new int; | | if (!m_pValue){ //already false | } | return m_pValue; | /*use *m_pValue */ *m_pValue = 42; | LeaveCriticalSection(); | </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload