Boost logo

Boost :

From: Alexander Terekhov (terekhov_at_[hidden])
Date: 2002-10-18 11:50:00


David Abrahams wrote:
>
> tss.html - ....

Speaking and/or thinking of TSD and TLS you might want to consider
the following: (don't miss ISO/EIC "edits" below)

Subject: Re: local statics and TLS objects
Date: 2002-10-11 05:37:42 PST

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: 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() );

< 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?


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk