3 ms·
Example: Thread 1 does A.lock, A.unlock, B.lock, B.unlock Thread 2 does B.lock, B.unlock, A.lock, A.unlock That's fine, but swap the middle pair of unlock fo
by atq2119 5y ago
Example:
Thread 1 does A.lock, A.unlock, B.lock, B.unlock
Thread 2 does B.lock, B.unlock, A.lock, A.unlock
That's fine, but swap the middle pair of unlock followed by lock on both threads and you have a standard deadlock based on different lock nestings.
And to reiterate from my previous comment, I do think that transform is or should be forbidden. That's not for synchronization reasons per se, but because the transform can change the set of externally visible side effects of the code. This argument requires that a store with release semantics is considered to be an externally visible side effect. That makes intuitive sense to me, though I don't remember what e.g. the C++ standard actually says about that.
- albertzeyer 5y agoIsn't this case discussed at the end of the article? > C++ committee member Tony Van Eerd commented on reddit that with std::memory_order_acquire and two locks a and b; calls to a.unlock(); b.lock() and lock() for different locks could be reordered to b.lock(); a.unlock(); and introduce a potential deadlock. I don’t think that’s true. Reading section 6.9.2.1 Data races (paragraph 9) of the C++ standard] no loads or stores can bed moved into or out from between a load-acquire and store-release pair. > http://eel.is/c++draft/intro.races#9 http://eel.is/c++draft/intro.races#9
- spacechild1 5y agoIt's true that the compiler can't move reads/write out from between a load-acquire and store-release pair, but in my understanding it can certainly move reads/writes into the pair. Or can someone point me to the exact section of the standard where this is prohibited? I think my stack overflow link above gives a more satisfying explanation on why the example can't deadlock.
- rigtorp 5y agoI now think it's actually this part of the standard that prevents it: http://eel.is/c++draft/intro.multithread#intro.progress-7 http://eel.is/c++draft/intro.multithread#intro.progress-7 Basically a compiler can not optimize a non-deadlocking program into a potentially deadlocking one.
- atq2119 5y agoYes, it's the same example, but the answer appears to be subtly different. Acquire and release are only "one-way barriers". Consider the link in the sibling comment by spacechild1.
- spacechild1 5y agoAlthough pure aquire-release semantics would allow such reordering, it also didn't feel quite right to me, either. Fortunately, someone asked the exact same question on Stack Overflow and got a good answer: https://stackoverflow.com/a/61300584 https://stackoverflow.com/a/61300584 Looks like you've been on the right track with regard to possible infinite loops.