Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019  2020  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019  2020 
<== Date ==> <== Thread ==>

Subject: Re: c++ static initialization
From: Andrew Johnson <anj@aps.anl.gov>
To: Benjamin Franksen <benjamin.franksen@helmholtz-berlin.de>
Cc: EPICS core-talk <core-talk@aps.anl.gov>
Date: Thu, 11 Aug 2011 14:58:55 -0500
Hi Benjamin,

On 2011-08-11 you wrote:
> 
> What I would try to avoid at all cost is non-trivial initialization in a
> *constructor* for a static object. I listed lazy initialization as one
> alternative possibility. Just to make sure we re talking about the same
> concept, what I mean is to add some code like
> 
>   if (!this->initialized) this->initialize();
> 
> at the start of each method. I may be wrong but I can't think of any
>  subsystem where this approach cannot be used instead of calling
>  initialize() from a constructor.

We're not really talking about constructing complicated objects, more the 
ability to run code at initialization time.  Take this example from libCom:

    static int done = timeRegister();

I don't care about the value of done, I just need to run the timeRegister() 
routine to register my time-proviers before anyone tries to ask for the 
current time.

Your code above is not SMP-safe, and actually it's not even safe on a UP 
system in some circumstances.  If there are at least two threads running then 
they can both execute the initialize() method simultaneously (before the other 
thread sets the initialized member), which is obviously a Bad Thing™.  You 
can't even protect the initialize() routine with its own mutex because someone 
has to create the mutex for the routine to lock.  The epicsThreadOnce() 
routine was designed to solve exactly this problem, and I believe we have 
already converted all the code in Base to use it.  The result looks like this:


static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;

static void once(void *junk)
{ ... }

FILE * epicsShareAPI doSomething(...)
{
    epicsThreadOnce(&onceId, once, 0);
    ...
}


If two threads on different CPUs call doSomething() simultaneously, one of 
them will execute the once() routine and the other one will be blocked until 
once() has returned.

Unfortunately with the existing implementation of epicsThreadOnce() every call 
to doSomething() results in a mutex lock and unlock of a single global mutex, 
which is obviously not good for parallelism and performance.  We don't want to 
incur that cost for some APIs that are used frequently, so lazy initialization 
isn't always a good idea.

> > On vxWorks and some RTEMS systems the NTPTimeSync and ClockTimeSync
> > threads are started from a static initializer, and they also get
> > registered with the taskwd subsystem which lazily starts its own thread
> > as a result:
> 
> As I said, starting threads lazily is not as evil as doing it directly from
>  a constructor for a static object, i.e. before main() starts.

SMP-safe lazy init requires making a call to epicsThreadOnce() every time you 
use that subsystem.  Hopefully we can remove the need to take a mutex every 
time by switching to atomic operations in 3.15, but we'll try to hide that 
from users and still make epicsThreadOnce() the API you use.

> I recognize that logging is one of the exceptions to my rule (1) but
>  (again) we can use lazy initialization here.

We already do.

> > > (5) epicsThreadOnce should also be avoided wherever possible. Using it
> > >
> > >  means objects cannot be freely passed between threads which is
> > > detriment to composability.
> >
> > But as Jeff implied, epicsThreadOnce() is essential to coding lazy
> > initialization correctly on an SMP system.
> 
> I would like to see the argument that leads to such a conclusion.

http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

- Andrew
-- 
Optimization is the process of taking something that works and
replacing it with something that almost works, but costs less.
-- Roger Needham


Replies:
Re: c++ static initialization Benjamin Franksen
References:
c++ static initialization Jeff Hill
Re: c++ static initialization Andrew Johnson
Re: c++ static initialization Benjamin Franksen

Navigate by Date:
Prev: Re: c++ static initialization Eric Norum
Next: RE: c++ static initialization Jeff Hill
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019  2020 
Navigate by Thread:
Prev: Re: c++ static initialization Eric Norum
Next: Re: c++ static initialization Benjamin Franksen
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019  2020 
ANJ, 02 Feb 2012 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·