C++ standard: can relaxed atomic stores be lifted above a mutex lock?

前端 未结 2 1360
予麋鹿
予麋鹿 2021-02-13 00:54

Is there any wording in the standard that guarantees that relaxed stores to atomics won\'t be lifted above the locking of a mutex? If not, is there any wording that explicitly s

2条回答
  •  萌比男神i
    2021-02-13 01:26

    I think I've figured out the particular partial order edges that guarantee the program can't crash. In the answer below I'm referencing version N4659 of the draft standard.

    The code involved for the writer thread A and reader thread B is:

    A1: mu.lock()
    A2: foo = 1
    A3: foo_has_been_set.store(relaxed)
    A4: mu.unlock()
    
    B1: foo_has_been_set.load(relaxed) <-- (stop if false)
    B2: mu.lock()
    B3: assert(foo == 1)
    B4: mu.unlock()
    

    We seek a proof that if B3 executes, then A2 happens before B3, as defined in [intro.races]/10. By [intro.races]/10.2, it's sufficient to prove that A2 inter-thread happens before B3.

    Because lock and unlock operations on a given mutex happen in a single total order ([thread.mutex.requirements.mutex]/5), we must have either A1 or B2 coming first. The two cases:

    1. Assume that A1 happens before B2. Then by [thread.mutex.class]/1 and [thread.mutex.requirements.mutex]/25, we know that A4 will synchronize with B2. Therefore by [intro.races]/9.1, A4 inter-thread happens before B2. Since B2 is sequenced before B3, by [intro.races]/9.3.1 we know that A4 inter-thread happens before B3. Since A2 is sequenced before A4, by [intro.races]/9.3.2, A2 inter-thread happens before B3.

    2. Assume that B2 happens before A1. Then by the same logic as above, we know that B4 synchronizes with A1. So since A1 is sequenced before A3, by [intro.races]/9.3.1, B4 inter-thread happens before A3. Therefore since B1 is sequenced before B4, by [intro.races]/9.3.2, B1 inter-thread happens before A3. Therefore by [intro.races]/10.2, B1 happens before A3. But then according to [intro.races]/16, B1 must take its value from the pre-A3 state. Therefore the load will return false, and B2 will never run in the first place. In other words, this case can't happen.

    So if B3 executes at all (case 1), A2 happens before B3 and the assert will pass. ∎

提交回复
热议问题