Re: Compiler ordering barriers in C++0x
  Home FAQ Contact Sign in
comp.lang.c++.moderated only
 
Advanced search
POPULAR GROUPS

more...

 Up
Re: Compiler ordering barriers in C++0x         

Group: comp.lang.c++.moderated · Group Profile
Author: Chris Thomasson
Date: May 5, 2008 05:49

"Szabolcs Ferenczi" gmail.com> wrote in message
news:e97bdaf4-5f8a-40bd-b058-46b30b1eb01a@x35g2000hsb.googlegroups.com...
> On May 3, 2:13 pm, Anthony Williams yahoo.com> wrote:
>> Szabolcs Ferenczi gmail.com> writes:
>>> On May 2, 12:43 pm, Anthony Williams 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! ]
no comments
diggit! del.icio.us! reddit!