Here is the header file defining the template: Based on a few answers, I made modifications to make template single thread safe. But the program still crashes, so I believe the focus here should not be if the template is thread safe. It's about what happened when C1 inherits from both CBase and Singleton. Apparently, the program crashes when C1 is trying to call the function of the member variable it's parent Class CBase. It seems to me, something is messed up in the memory when multiple inheritance and the single template are used together.
#ifndef _T_SINGLETON_HH_
#define _T_SINGLETON_HH_
template <class T>
class Singleton
{
public:
static T* getInstance()
{
static T instance_;
return &instance_;
}
template <class A>
static T* getInstance(A a)
{
static T instance_(a);
return &instance_;
}
protected:
Singleton() {}
virtual ~Singleton() {}
private:
Singleton(Singleton const&);
Singleton& operator=(Singleton const&);
};
#endif // _T_SINGLETON_HH_ //
And here is how this template was used:
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include "singleton.hh"
using namespace std;
class X;
class X1;
class ABase;
class BBase;
class BB;
class CBase;
class X {
public:
virtual int getX() = 0;
};
class X1 : public X {
public:
int getX() { return 1; }
};
class Timer
{
private:
static Timer* t_;
BBase* b_;
Timer();
static void* go_helper(void* context);
void go();
public:
virtual ~Timer() {}
static Timer* getInstance();
void subscribe(BBase* b);
void unsubscribe(BBase* b) { b_ = NULL; }
};
class CBase {
public:
CBase(BB& bb) : bb_(bb) {}
virtual void run() = 0;
protected:
BB& bb_;
};
class C1 : public CBase,
public Singleton<C1>
{
public:
C1(BB& bb) : CBase(bb) {}
void run();
};
class BBase {
public:
BBase(ABase& a) : a_(a) { Timer::getInstance()->subscribe(this); }
virtual ~BBase() { Timer::getInstance()->unsubscribe(this); }
virtual void run() = 0;
protected:
ABase& a_;
};
class BB : public BBase {
public:
BB(ABase& a) : BBase(a) {
c = C1::getInstance(*this);
// c = new C1(*this); IF WE USE THIS INSTEAD, THEN IT WILL WORK
}
int getX();
void run();
private:
CBase* c;
};
class ABase {
public:
ABase() {
x = new X1;
b = new BB(*this);
}
void run();
int getX() { return x->getX(); }
private:
X* x;
BBase* b;
};
Timer* Timer::t_ = NULL;
Timer::Timer() : b_(NULL)
{
pthread_t th;
pthread_create(&th, NULL, &Timer::go_helper, this);
}
Timer*
Timer::getInstance() {
if (t_ == NULL)
t_ = new Timer;
return t_;
}
void
Timer::subscribe(BBase* b) { b_ = b; }
void*
Timer::go_helper(void* context) {
Timer *t = reinterpret_cast<Timer*>(context);
t->go();
return NULL;
}
void
Timer::go()
{
while(1) {
sleep(1);
if (b_) b_->run();
}
}
void ABase::run() {
cout << __PRETTY_FUNCTION__ << getX() << endl;
cout << __PRETTY_FUNCTION__ << x->getX() << endl;
b->run();
while(1)
sleep(1);
}
int BB::getX() {
return a_.getX();
}
void BB::run() {
cout << __PRETTY_FUNCTION__ << endl;
c->run();
}
void C1::run() {
cout << __PRETTY_FUNCTION__ << bb_.getX() << endl;
}
int main()
{
ABase* a = new ABase;
a->run();
}
If you still think it is a thread safe issue, then here is the simplified one thread version using the template:
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include "singleton.hh"
using namespace std;
class X;
class X1;
class ABase;
class BBase;
class BB;
class CBase;
class X {
public:
virtual int getX() = 0;
};
class X1 : public X {
public:
int getX() { return 1; }
};
class CBase {
public:
CBase(BB& bb) : bb_(bb) {}
virtual void run() = 0;
protected:
BB& bb_;
};
class C1 : public CBase,
public Singleton<C1>
{
public:
C1(BB& bb) : CBase(bb) {}
void run();
};
class BBase {
public:
BBase(ABase& a) : a_(a) { }
virtual ~BBase() { }
virtual void run() = 0;
protected:
ABase& a_;
};
class BB : public BBase {
public:
BB(ABase& a) : BBase(a) {
c = C1::getInstance(*this);
// c = new C1(*this);
}
int getX();
void run();
private:
CBase* c;
};
class ABase {
public:
ABase() {
x = new X1;
b = new BB(*this);
}
void run();
int getX() { return x->getX(); }
private:
X* x;
BBase* b;
};
void ABase::run() {
cout << __PRETTY_FUNCTION__ << getX() << endl;
cout << __PRETTY_FUNCTION__ << x->getX() << endl;
b->run();
while(1)
sleep(1);
}
int BB::getX() {
return a_.getX();
}
void BB::run() {
cout << __PRETTY_FUNCTION__ << endl;
c->run();
}
void C1::run() {
cout << __PRETTY_FUNCTION__ << bb_.getX() << endl;
}
When I run this program, it crashes:
void ABase::run()1
void ABase::run()1
virtual void BB::run()
zsh: segmentation fault (core dumped) ./a.out
Here is the stack information given by GDB:
#0 0x00000000004012ba in ABase::getX (this=0x1) at tst_sigill.cc:89
89 int getX() { return x->getX(); }
[Current thread is 1 (Thread 0x7faa0f050740 (LWP 5351))]
(gdb) bt
#0 0x00000000004012ba in ABase::getX (this=0x1) at tst_sigill.cc:89
#1 0x0000000000400e0c in BB::getX (this=0x7ffed6e821f0) at tst_sigill.cc:138
#2 0x0000000000400e71 in C1::run (this=0xaeedd0) at tst_sigill.cc:146
#3 0x0000000000400e51 in BB::run (this=0xaeec60) at tst_sigill.cc:142
#4 0x0000000000400de3 in ABase::run (this=0xaeec20) at tst_sigill.cc:132
#5 0x0000000000400ed1 in main () at tst_sigill.cc:152
For some unknown reason, this pointer passed to BB::getX and ABase::getX was messed up. I can't see what's wrong with the code.