You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
However, I don't understand why it works. The memory_order_acquire just make sure that all memory operations can not be moved before it. But flag.test_and_set contains a write operation after the read. And I think the write operation has relax memory order with the above code. That means if there are 2 threads that call the lock() simultaneously:
Firstly, thread1's flag.test_and_set returns false and writes true into flag, but with relax memory order.
Then, thread2's flag.test_and_set use acquire to read the data in flag, but it may not read the true set by thread 1, since thread 1's write is using relax memory order. Then thread2 may get false too, and it can also pass the lock and enter the critical section.
So I think it should use std::memory_order_acq_rel to make the logic correct.
Can you tell me what's wrong with my understanding?
Thanks
The text was updated successfully, but these errors were encountered:
I also have understanding similar to yours.
This book also has:
If you use read-modify-write operations, it’s important to pick which semantics you desire. In this case, you want both acquire and release semantics, so memory_order_acq_rel is appropriate, but you can use other orderings too. A fetch_sub operation with memory_order_acquire semantics doesn’t synchronize with anything, even though it stores a value, because it isn’t a release operation. Likewise, a store can’t synchronize with a fetch_or with memory_order_release semantics, because the read part of the fetch_or isn’t an acquire operation. Read-modify-write operations with memory_order_acq_rel semantics behave as both an acquire and a release, so a prior store can synchronize with such an operation, and it can synchronize with a subsequent load, as is the case in this example.
Read-modify-write operations such as test_and_set are still atomic, and the read and write portions are inseparable. Thus if you have two calls to flag.test_and_set then one will be first and one will be second. If the flag was initially not set, then the "first" call will return false and the "second" call will return true. This is independent of the memory ordering passed: it still works with memory_order_relaxed. The memory ordering specified provides the synchronization on other operations: those on the data protected by the mutex.
For the spinlock code, the lock logic is as follows:
However, I don't understand why it works. The
memory_order_acquire
just make sure that all memory operations can not be moved before it. Butflag.test_and_set
contains a write operation after the read. And I think the write operation has relax memory order with the above code. That means if there are 2 threads that call thelock()
simultaneously:flag.test_and_set
returnsfalse
and writestrue
intoflag
, but with relax memory order.flag.test_and_set
use acquire to read the data inflag
, but it may not read thetrue
set by thread 1, since thread 1's write is using relax memory order. Then thread2 may getfalse
too, and it can also pass the lock and enter the critical section.So I think it should use
std::memory_order_acq_rel
to make the logic correct.Can you tell me what's wrong with my understanding?
Thanks
The text was updated successfully, but these errors were encountered: