Mark,

On 9/15/15 3:29 PM, Mark Thomas wrote:
> On 15/09/2015 17:59, Yilong Li wrote:
>> On Tue, Sep 15, 2015 at 7:19 AM, Mark Thomas <ma...@apache.org> wrote:
> 
>>> Long experience has lead us to be sceptical of bugs reported by
>>> automated tools. When looking at such bugs and we can't see what the
>>> problem is and the person raising the bug can't provide a clear
>>> explanation - and continues not to provide a clear explanation when
>>> asked for one several times - then that is the point where we start to
>>> think the problem is with the tool.
>>>
>>
>> Sorry, I should not assume that the concepts such as happens-before order
>> and memory model are well understood. Let's talk about how this is allowed
>> to happen under JMM. Consider the this example again:
>>
>> if (st_200 == null ) {
>>     st_200 = sm.getString("sc.200");
>> }
>> return st_200;
>>
>> The following is a valid execution trace consists of 5 events:
>>             T1                       T2
>> 1   READ  null
>> 2   WRITE s
>> 3                                 READ s
>> 4                                 READ ???
>> 5   READ  s
>>
>> , where s is the result of sm.getString("sc.200").
>>
>> T1 sees null in field st_200, initializes it, and return the initialized
>> value, while T2 sees a non-null value in st_200 and skips the
>> initialization. The question is what value T2 can read and then return in
>> event 4. This is addressed in JLS $17.4.5 Happens-before Order (
>> https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.5):
>>
>> We say that a read *r* of a variable *v* is allowed to observe a write *w*
>> to *v* if, in the *happens-before* partial order of the execution trace:
>>
>>    -
>>
>>    *r* is not ordered before *w* (i.e., it is not the case that *hb(r, w)*),
>>    and
>>    -
>>
>>    there is no intervening write *w*' to *v* (i.e. no write *w*' to *v* such
>>    that *hb(w, w')* and *hb(w', r)*).
>>
>> Informally, a read *r* is allowed to see the result of a write *w* if there
>> is no *happens-before* ordering to prevent that read.
>>
>> The question boils down to: does the write in event 2 prevent event 4 from
>> reading the initial null value of st_200? No, because there is no
>> happens-before order involved here. So what kind of constructs introduce
>> happens-before order? This question is also addressed in the same section
>> of JLS:
>>
>> It follows from the above definitions that:
>>
>>    -
>>
>>    An unlock on a monitor *happens-before* every subsequent lock on that
>>    monitor.
>>    -
>>
>>    A write to a volatile field (ยง8.3.1.4
>>    <https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.3.1.4>
>>    ) *happens-before* every subsequent read of that field.
>>    -
>>
>>    A call to start() on a thread *happens-before* any actions in the
>>    started thread.
>>    -
>>
>>    All actions in a thread *happen-before* any other thread successfully
>>    returns from a join() on that thread.
>>    -
>>
>>    The default initialization of any object *happens-before* any other
>>    actions (other than default-writes) of a program.
> 
> Thank you. That helps fill in a few gaps. Putting it into my own words
> to check my understanding:
> 
> - The two reads in T2 may be re-ordered because, in T2, there is nothing
>   that requires a happens-before relationship between the two reads
> 
> - If T2 was executing in isolation the order of the reads wouldn't
>   matter
> 
> - However, T1 is writing.
> 
> So if the writes in T2 are re-ordered and the write from T1 takes place
> between them the T2 read for the line 'st_200 == null' could return a
> non-null value for st_200 (the value after the write from T1) while the
> read for the line 'return st_200;' could return null (the value from
> before the write in T1).
> 
> Is my understanding correct?

That sounds crazy (but may actually be correct).

I don't see why a thread would read one value from memory and then have
that value change locally without going back to main memory. T1 can only
affect its own local views of the references and, of course, main
memory. Once T1 writes to main memory, T2 can see the changes. I don't
think the JMM allows threads to change other threads' references
directly without writing to main memory.

I don't think that T2 can read non-null and then later read null given
the code we are discussing. If T1 writes /null/ to main memory, then
this can happen,but I think we can all agree T1 is *not* gong to write null.

>>> I don't have any particular issues in mind, just a suspicion that
>>> concurrency issues lie behind some of the hard to reproduce bugs that
>>> get reported from time to time. If I could produce the bug I would have
>>> fixed it already.
>>>
>>
>> Technically speaking, RV-Predict doesn't require a developer to be able to
>> produce the bug or data race in order to detect it. One can run RV-Predict
>> on code that fails only intermittently and RV-Predict may still catch the
>> bug. Perhaps it can be helpful to ask the bug reporter to run their code
>> against RV-Predict if it's just too hard to extract a test case that can
>> reproduce the failure consistently enough.
> 
> Good to know. That is certainly worth a try. I'll add something to the
> bugs in question.
> 
>> Thanks again for the prompt responses and the quick fixes of the reported
>> bugs. This has also helped RV-Predict to get into a better shape.
> 
> Thanks to you to. It has certainly helped Tomcat improve and the
> discussion around these issues continues to help educate the community
> as a whole about these issues.

+1

I hope it's more than the small group of us reading these messages :)

-chris

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to