patterncppModerate
Macro to run code once during the lifetime of the program
Viewed 0 times
oncelifetimetheduringprogrammacrocoderun
Problem
I'm using this little macro a lot:
I find it useful when I want to initialize stuff just once when I don't really care about performance (for example, if it's inside a render loop, it takes just 60 if's per sec). In a random generator, I can do
I'd like to know if any of you use a similar system, and if there's better way of doing this. Or if I should stop using this method immediately...
#define RUN_ONCE(runcode) \
{ \
static bool code_ran = 0; \
if(!code_ran){ \
code_ran = 1; \
runcode; \
} \
}I find it useful when I want to initialize stuff just once when I don't really care about performance (for example, if it's inside a render loop, it takes just 60 if's per sec). In a random generator, I can do
RUN_ONCE(init_random()), so I don't need to separately initialize it, which prevents me from crashing when I call the function without initializing it first.I'd like to know if any of you use a similar system, and if there's better way of doing this. Or if I should stop using this method immediately...
Solution
It is not thread safe. You can use Boost, or standard C++11
Answer to comment:
Boost and C++11 are defining include library for launching threads and thread synchronization (locks, atomic variables…). The
A very simplified (unefficent) implementation might be:
It is not very efficient because the lock is always taken. An optimisation it to atomically check the once flag before taking the mutex:
The implementation of
Boost/C++11 use a functor (function pointer or object with
std::call_once.Answer to comment:
Boost and C++11 are defining include library for launching threads and thread synchronization (locks, atomic variables…). The
call_once function can either use those to ensure thread safety or use the thread lib of the OS (pthreads for *nix).A very simplified (unefficent) implementation might be:
static std::mutex mutex;
static bool called = false;
{
std::lock_guard lock(mutex);
if (!called) {
f(); // <- User code
called = true;
}
}It is not very efficient because the lock is always taken. An optimisation it to atomically check the once flag before taking the mutex:
static std::mutex mutex;
static std::atomic called = false;
{
if (!called) {
std::lock_guard lock(mutex);
if (!called) {
f(); // <- User code
called = true;
}
}
}The implementation of
pthread_once in glibc is interesting: it is much more complicated as it tries to behave correctly in presence of fork.Boost/C++11 use a functor (function pointer or object with
operator()): this way it can be implemented as a function and not a macro (you can use lambda in C++11 to avoid defining a separate function).Code Snippets
static std::mutex mutex;
static bool called = false;
{
std::lock_guard<std::mutex> lock(mutex);
if (!called) {
f(); // <- User code
called = true;
}
}static std::mutex mutex;
static std::atomic<bool> called = false;
{
if (!called) {
std::lock_guard<std::mutex> lock(mutex);
if (!called) {
f(); // <- User code
called = true;
}
}
}Context
StackExchange Code Review Q#4422, answer score: 18
Revisions (0)
No revisions yet.