Re: initializing static variable (multiple threads)
If your compiler does not make this threadsafe, then Init() may indeed
be called multiple times. You may also find that some threads skip
calling Init() and read the value of i as it stands at that point, even
though another thread is still running Init() (and thus hasn't stored
the new value in i yet). Such threads may thus get a random value.
Hi,
This is a very good point. I was 'prepared' for multiple
initializations, but not for reading an uninitialized variable.
I need to share a static local variable between multiple threads. The
variable is local to the foo() function (see below), that usually just
reads the variable. The Set() function will modify the variable. I
need to make foo() as fast as possible, so I don't want to use any
lock on the normal path. I can use locks in Set() and on the
initialization path inside foo() (Init()).
The code is supposed to be part of a reusable library, and it should
be portable.
Will this work?
#include <boost/thread/mutex.hpp>
const int NOT_INIT = -1;
const int INIT = 0;
int SafeRead(volatile int& i);
int SafeWrite(int i, volatile int& i);
void Init(volatile int& i);
boost::mutex m;
volatile int* ptrI = 0;
void foo()
{
static volatile int i = NOT_INIT; // static initialization, before
foo() is first called
int local_i = SafeRead(i);
if (local_i == NOT_INIT)
{
Init(i);
local_i = SafeRead(i);
}
//... use the local_i here read/only
}
void Init(volatile int& i)
{
boost::mutex::scoped_lock l(m);
if (i != NOT_INIT)
return;
ptrI = &i;
SafeWrite(INIT, *ptrI);
}
void Set(unsigned i) // called from a separate thread; it does nothing
until foo() gets called, then it can set the local static variable
{
boost::mutex::scoped_lock l(m);
if (ptrI != 0)
SafeWrite(i, *ptrI);
}
SafeRead()/SafeWrite() will use memory barriers to get/set the shared
data.
(for example I could use http://www.hpl.hp.com/research/linux/atomic_ops
to implement them in a portable way)
Is the above code thread-safe?
To recap: the goal is to share a static local variable between
threads; it is ok that Init() and Set() to be slower (and use locks)
as long as the foo() normal path is very fast (no locking);
1. the shared variable has an 'int' type (native machine size)
2. used 'volatile' to disable compile time optimizations
3. used SafeRead()/SafeWrite() and insert appropriate memory barriers
(disabling execution reordering)
4. the 'i' variable is statically initialized (before foo() is
called)
Many thanks,
Petru
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]