Re: question re. usage of "static" within static member functions of a class
"Chris M. Thomasson" <no@spam.invalid> wrote in message
news:h8bb27$2qla$1@news.ett.com.ua...
"Joshua Maurice" <joshuamaurice@gmail.com> wrote in message
[...]
Alternatively, use a namespace scope variable to force construction
before main (or before dlopen returns for static init of a dll) to
"guarantee" correctness as demonstrated in countless posts in this
thread.
Humm...
There is really no "guarantee" of correctness wrt this technique in the
presence of threads because it is not thread-safe in any way, shape or form.
It's not a general purpose construct unless there is explicit documentation
that documents all the caveats.
I can easily break the heck out of it. For instance, check this crap out:
_____________________________________________________________________
#include <pthread.h>
#include <sched.h>
#include <cstdio>
void yield()
{
for (unsigned i = 0; i < 10; ++i)
{
sched_yield();
}
}
template<typename T, unsigned T_id = 0>
class non_destroying_singleton
{
static T* g_instance;
public:
static T& instance();
};
template<typename T, unsigned T_id>
T& non_destroying_singleton<T, T_id>::instance()
{
yield();
if (! g_instance)
{
yield();
g_instance = new T();
yield();
}
yield();
return *g_instance;
}
template<typename T, unsigned T_id>
T* non_destroying_singleton<T, T_id>::g_instance =
&non_destroying_singleton<T, T_id>::instance();
struct foo
{
foo()
{
std::printf("(%p)->foo::foo()\n", (void*)this);
}
~foo()
{
std::printf("(%p)->foo::~foo()\n", (void*)this);
}
};
extern "C"
void* killer_thread(void*)
{
std::puts("killer_thread");
non_destroying_singleton<foo>::instance();
return NULL;
}
struct killer
{
pthread_t m_tid[10];
killer()
{
std::puts("killer::killer()");
for (unsigned i = 0; i < 10; ++i)
{
pthread_create(&m_tid[i], NULL, killer_thread, NULL);
}
}
~killer()
{
std::puts("killer::~killer()");
for (unsigned i = 0; i < 10; ++i)
{
pthread_join(m_tid[i], NULL);
}
}
};
static killer g_killer;
int
main()
{
std::puts("main");
return 0;
}
_____________________________________________________________________
Oh shi%! Massive race-condition here... `foo' can be created multiple times
and leaked all over the damn place. Here is the output I happened to get:
_____________________________________________________________________
killer::killer()
killer_thread
killer_thread
killer_thread
killer_thread
killer_thread
killer_thread
(0024B7B8)->foo::foo()
killer_thread
killer_thread
(0024B808)->foo::foo()
(0024B818)->foo::foo()
(0024B828)->foo::foo()
killer_thread
killer_thread
main
killer::~killer()
_____________________________________________________________________
KA-BOOOOOOM!!!!!!!!!!!
:^o
If you are fine with leaking the singleton and are a disciplined
programmer, then it will work.
You need to be very disciplined.
;^)