Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

local statics and TLS objects

9 views
Skip to first unread message

Alexander Terekhov

unread,
Oct 10, 2002, 10:42:42 AM10/10/02
to

< was: Re: volatile -- what does it mean in relation to member functions?
comp.lang.c++.moderated >

James Kanze wrote:
[...]
> > > Posix says nothing about C++. A C++ compiler can do what it wants,
> > > and not affect Posix compliance. Still, I can't imagine a C++
> > > compiler not extending the guarantees of C to cover its operations.
> > > (It does mean, however, that a fair number of C++ compilers do not
> > > generate thread safe code, particularly when it comes to
> > > initializing local statics.
[...]
> > Been there done that. That static local initialization doesn't work in
> > a lot of compilers is very unfortunate. Since the C++ standard clearly
> > says that it should be initialized on the first call there's really no
> > excuse. It doesn't say under which circumstances so this means this
> > should hold under *any* circumstances and if your compiler even has a
> > switch to notify it about multithreaded code...
>
> I tend to agree with you here. ....

I disagree. And, BTW, I'd be quite happy to be able to write
something like:

ThreadLocalLazySingleton&
ThreadLocalLazySingleton::get() // static
{
// Kinda "static" but might throw std::bad_alloc even
// if used with throw() [throw nothing] constructor[1].
static(thread_private) ThreadLocalLazySingleton thing(/**/);
return thing;
}

and

GlobalLazyImmutableSingleton const&
GlobalLazyImmutableSingleton::get() // static
{
// Thread shared/safe version of "classic" local static. See
// the link below (i.e. it's synchronized using __cxa__guards).
static(thread_shared) const GlobalLazyImmutableSingleton thing(/**/);
return thing;
}

leaving

ThreadsUnawareGlobalLazySingleton&
ThreadsUnawareGlobalLazySingleton::get() // static
{
// This thing is "single threaded" -- NOT meant to use
// http://www.codesourcery.com/cxx-abi/abi.html#once-ctor
// "sync-guards"/synchronization-by-default
static ThreadsUnawareGlobalLazySingleton thing(/**/);
return thing;
}

alone (with respect to threading)... for things like:

// Module

static ReadWriteLock s_lock;

LazySingletonWithReadWriteAccess*
LazySingletonWithReadWriteAccess::s_inst = 0; // set in c-tor

auto_unlock_ptr< LazySingletonWithReadWriteAccess >
LazySingletonWithReadWriteAccess::getForWrite() // static
{
ReadWriteLock::WriteGuard guard( s_lock );
static LazySingletonWithReadWriteAccess thing(/**/);
return auto_unlock_ptr<
LazySingletonWithReadWriteAccess >(&thing,guard);
}

auto_unlock_ptr< const LazySingletonWithReadWriteAccess >
LazySingletonWithReadWriteAccess::getForRead() // static
{
{
ReadWriteLock::ReadGuard guard( s_lock );
if ( s_inst )
return auto_unlock_ptr<
const LazySingletonWithReadWriteAccess >(s_inst,guard);
}
return getForWrite().degradeToReadOnlyAccess();
}

Or am I just missing and/or misunderstanding something?

How is this currently done by the existing C++ implementations
that already provide TLS (supporting constructors/destructors)?

regards,
alexander.

[1] So, basically:

extern void operation( Something& );
extern(thread_private) Something thing = blah_blah;

/* ... */

operation( thing );

would actually mean something along the lines of:

extern void operation( Something& );
extern Something& __thing() // throw( std::bad_alloc, ... )
{
static(thread_private) Something thing = blah_blah;
return thing;
}

operation( __thing() );

Alexander Terekhov

unread,
Oct 11, 2002, 8:38:02 AM10/11/02
to

Alexander Terekhov wrote:
>

Well, "thread-private" was a bit confusing. I should have used something
like "thread-local". Also... Momchil, see yet another "fixed" DCL below.

< was: Re: Talking about volatile and threads synchronization... >

Momchil Velikov wrote:
[...]
> So, the DCL case will looke like this, right ?
>
> void foo ()
> {
> static int initialized;
> int i;
>
> i = initialized;
>
> /* Read memory barrier, so the above read of ``initialized''
> is issued before reads of memory, initialized by ``do_stuff''.
> We may not need this on some architectures. Which ones ? */
> rmb ();
> if (i == 0)
> {
> lock ();
> if (initialized == 0)
> {
> do_stuff ();
>
> /* Write memory barrier - prevent CPU from reordering
> writes across this point. Necessary (but not
> necessarily sufficient) to ensure the reader sees
> the new values written in ``do_stuff''
> whenever it sees ``initialized'' being nonzero. */
> wmb ();
> initialized = 1;
> }
> unlock ();
> }
>
> do_more_stuff ();
> }

Nah, given the following {rather intereseting(*)}
"ISO/EIC xxxx:xxxx edits": ;-)

http://gcc.gnu.org/onlinedocs/gcc/C99-Thread-Local-Edits.html#C99%20Thread-Local%20Edits
(ISO/IEC 9899:1999 Edits for Thread-Local Storage)

http://gcc.gnu.org/onlinedocs/gcc/C--98-Thread-Local-Edits.html#C++98%20Thread-Local%20Edits
(ISO/IEC 14882:1998 Edits for Thread-Local Storage)

So, the DCL case will look like this:

void foo ()
{
static int initializedGlobal;
static __thread int initializedThreadLocal;

if (initializedThreadLocal == 0)
{
lock ();
if (initializedGlobal == 0)
{
do_stuff ();

initializedGlobal = 1;
}
unlock ();

initializedThreadLocal = 1;
}

do_more_stuff ();
}

regards,
alexander.

(*) Does DEC's/Compaq's/NewHP's TLS have the same "semantics" with
respect to non-lazy/eager "static" TLS inits -- NOT supporting
dynamic initialization/C++ c-tors? What about dlopen(), then?

0 new messages