Re: Compiler ordering barriers in C++0x
"Szabolcs Ferenczi" <szabolcs.ferenczi@gmail.com> wrote in message
news:e97bdaf4-5f8a-40bd-b058-46b30b1eb01a@x35g2000hsb.googlegroups.com...
On May 3, 2:13 pm, Anthony Williams <anthony_w....@yahoo.com> wrote:
Szabolcs Ferenczi <szabolcs.feren...@gmail.com> writes:
On May 2, 12:43 pm, Anthony Williams <anthony_w....@yahoo.com> wrote:
[...]
All accesses to shared data MUST be synchronized with atomics: [...]
Can you elaborate this point please. How can you generally synchronise
N processes with help of atomics? Do you mean only two processes under
certain circumstances?
If any thread modifies shared data that is not of type atomic_xxx, the
developer must ensure appropriate synchronization with any other thread
that
accesses that shared data in order to avoid a data race (and the
undefined
behaviour that comes with that).
It is clear that you must synchronise access to shared variable.
Normally you must use a Critical Region for that.
I was curious how do you synchronise access to shared data with
atomics.
Really? How do you think some mutexs, semaphores, non-blocking algorithms
ect, ect, are actually implemented? IMHO, C++ should be at a low enough
level to create fairly efficient custom sync primitives. You can use atomics
to create different forms of reader-writer patterns. Are you familiar with
basic concepts of RCU?
Note that atomics only provide this synchronisation for the
access of the atomics themselves but you claimed something like with
atomics you can synchronise access to non-atomic shared data. How? Can
you provide example, please.
[...]
Here is one way to use atomics:
#ifndef MUTEX_ERROR_UNEXPECTED
# define MUTEX_ERROR_UNEXPECTED assert(false), std::unexcepted
#endif
class mutex {
enum constant {
UNLOCKED = 0,
LOCKED = 1,
CONTENTION = 2
};
atomic_word m_state;
os_event m_waitset;
public:
mutex() : m_state(UNLOCKED), (os_event_create(...)) {
if (m_waitset == OS_EVENT_INVALID) {
throw std::exception();
}
}
~mutex() throw() {
if (m_state != UNLOCKED || ! os_event_destroy(m_waitset)) {
MUTEX_ERROR_UNEXPECTED();
}
}
void lock() throw() {
if (ATOMIC_SWAP(&m_state, LOCKED)) {
while (ATOMIC_SWAP(&m_state, CONTENTION)) {
if (! os_event_wait(m_waitset)) {
MUTEX_ERROR_UNEXPECTED();
}
}
}
MEMBAR #StoreLoad | #StoreStore;
}
bool trylock() throw() {
if (! ATOMIC_CAS(&m_state, UNLOCKED, LOCKED)) {
return false;
}
MEMBAR #StoreLoad | #StoreStore;
}
void unlock() throw() {
MEMBAR #LoadStore | #StoreStore;
if (ATOMIC_SWAP(&m_state, UNLOCKED) == CONTENTION) {
if (! os_event_set(m_waitset)) {
MUTEX_ERROR_UNEXPECTED();
}
}
}
};
;^)
Do you think that C++ should _not_ be at a level that is low enough to
create custom non-blocking synchronization primitives?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]