M
Michael Podolsky
Hi Everyone,
My question is about the memory model in the context of C++11
standard.
1. The standard does not demand mutex operations to be all totally
ordered (memory_order_seq_cst), nor demand them to have
memory_order_acq_rel semantics for lock() operation. From various
parts of the standard it may be inferred that lock() operation should
have memory_order_acquire semantics and unlock() operation -
memory_order_release semantics.
2. I then should ask the question: which part of the standard prevents
lock() and unlock() operations on DIFFERENT mutexes to be reorered,
i.e. what prevents the following sequence:
m1.lock();
m1.unlock();
m2.lock();
m2.unlock();
to be compiled into:
m1.lock();
m2.lock();
m1.unlock();
m2.unlock();
which obviously must not be allowed because of potential deadlocks.
3. If the answer to the previous question is some special knowledge of
compiler of mutex objects, I should then ask the same question for a
hypothetical hand-made synchronization object, like a spin-lock,
implemented via atomic operations with memory_order_acquire for
lock() and memory_order_release on unlock(). The same question should
be asked here - does the standard prohibit (and by which exactly
paragraph if you may make the reference) reordering of unlock() and a
following lock() operations for such a hand-made object which may
internally use
atomic<int>::store(0, memory_order_release) for unlock
and then
atomic<int>::exchange(1, memory_order_acquire) for lock?
Note again that these operation are running on DIFFERENT memory
locations, i.e. the question is now reformulated like: what prohibits
the following reordering
from
while( atomic1.exchange(1, memory_order_acquire) ){;}
// critical section protected by atomic1
atomic1.store(0, memory_order_release);
while( atomic2.exchange(1, memory_order_acquire) ){;}
// critical section protected by atomic2
atomic2.store(0, memory_order_release);
to
while( atomic1.exchange(1, memory_order_acquire) ){;}
while( atomic2.exchange(1, memory_order_acquire) ){;}
atomic1.store(0, memory_order_release);
atomic2.store(0, memory_order_release);
Regards,
Michael
My question is about the memory model in the context of C++11
standard.
1. The standard does not demand mutex operations to be all totally
ordered (memory_order_seq_cst), nor demand them to have
memory_order_acq_rel semantics for lock() operation. From various
parts of the standard it may be inferred that lock() operation should
have memory_order_acquire semantics and unlock() operation -
memory_order_release semantics.
2. I then should ask the question: which part of the standard prevents
lock() and unlock() operations on DIFFERENT mutexes to be reorered,
i.e. what prevents the following sequence:
m1.lock();
m1.unlock();
m2.lock();
m2.unlock();
to be compiled into:
m1.lock();
m2.lock();
m1.unlock();
m2.unlock();
which obviously must not be allowed because of potential deadlocks.
3. If the answer to the previous question is some special knowledge of
compiler of mutex objects, I should then ask the same question for a
hypothetical hand-made synchronization object, like a spin-lock,
implemented via atomic operations with memory_order_acquire for
lock() and memory_order_release on unlock(). The same question should
be asked here - does the standard prohibit (and by which exactly
paragraph if you may make the reference) reordering of unlock() and a
following lock() operations for such a hand-made object which may
internally use
atomic<int>::store(0, memory_order_release) for unlock
and then
atomic<int>::exchange(1, memory_order_acquire) for lock?
Note again that these operation are running on DIFFERENT memory
locations, i.e. the question is now reformulated like: what prohibits
the following reordering
from
while( atomic1.exchange(1, memory_order_acquire) ){;}
// critical section protected by atomic1
atomic1.store(0, memory_order_release);
while( atomic2.exchange(1, memory_order_acquire) ){;}
// critical section protected by atomic2
atomic2.store(0, memory_order_release);
to
while( atomic1.exchange(1, memory_order_acquire) ){;}
while( atomic2.exchange(1, memory_order_acquire) ){;}
atomic1.store(0, memory_order_release);
atomic2.store(0, memory_order_release);
Regards,
Michael