Singleton class fails on reboot

G

Guest

Hi,

I am writing a windows service. The code runs fine when I start the
service when my machine is running but
it fails to start automatically when the machine reboots. The code
bombs out when it reaches code that tries to access
a singleton class. This is the code.



void ClientLogging::initClientErrorLog(InstallationInfo install)
{

// next line fails on a reboot
string szLogLevel =
ConfigManager::Instance().getConfigMgrValue("LOG_LEVEL");

Logging::Instance().Initialize("IseeCltLog");

Logging::LogLevel severity =
Logging::Instance().toSeverity(szLogLevel);

m_pFileLogAppender = new FileLogAppender(severity, logFile); //this
line fails on reboot
if(false == Logging::Instance().addAppender(m_pFileLogAppender))
{

}

}



The strange thing is ClientLogging is also a singleton, the first one
that is called, and this works fine.
This is called using:

ClientLogging::Instance().initClientErrorLog(install);

But it is inside this that the problems arise, on the line as seen
above

string szLogLevel =
ConfigManager::Instance().getConfigMgrValue("LOG_LEVEL");

The code just terminates.


Is there anything I can do to prevent this, any pragma.
Could this be because I initialize static variables.


Your help would be greatly appreciated.


Enda
 
D

Doug

Hi,

I am writing a windows service. The code runs fine when I start the
service when my machine is running but
it fails to start automatically when the machine reboots. The code
bombs out when it reaches code that tries to access
a singleton class. This is the code.



void ClientLogging::initClientErrorLog(InstallationInfo install)
{

// next line fails on a reboot
string szLogLevel =
ConfigManager::Instance().getConfigMgrValue("LOG_LEVEL");

Logging::Instance().Initialize("IseeCltLog");

Logging::LogLevel severity =
Logging::Instance().toSeverity(szLogLevel);

m_pFileLogAppender = new FileLogAppender(severity, logFile); //this
line fails on reboot
if(false == Logging::Instance().addAppender(m_pFileLogAppender))
{

}

}



The strange thing is ClientLogging is also a singleton, the first one
that is called, and this works fine.
This is called using:

ClientLogging::Instance().initClientErrorLog(install);

But it is inside this that the problems arise, on the line as seen
above

string szLogLevel =
ConfigManager::Instance().getConfigMgrValue("LOG_LEVEL");

The code just terminates.


Is there anything I can do to prevent this, any pragma.
Could this be because I initialize static variables.


Your help would be greatly appreciated.


Enda

Your second flagged failure involves file access. I'm guessing your
first flagged failure also involves file access (maybe reading a config
file?)

I can only think of one thing - a security issue: the user your service
is starting as after a reboot is not the same user as you are when you
start it manually, and the former doesn't have access rights to the
required files?

But I'm probably wrong...

I think the singleton thing is a red herring.

Doug
 
H

Howard

Hi,

I am writing a windows service. The code runs fine when I start the
service when my machine is running but
it fails to start automatically when the machine reboots. The code
bombs out when it reaches code that tries to access
a singleton class. This is the code.



void ClientLogging::initClientErrorLog(InstallationInfo install)
{

// next line fails on a reboot
string szLogLevel =
ConfigManager::Instance().getConfigMgrValue("LOG_LEVEL");

Logging::Instance().Initialize("IseeCltLog");

Logging::LogLevel severity =
Logging::Instance().toSeverity(szLogLevel);

m_pFileLogAppender = new FileLogAppender(severity, logFile); //this
line fails on reboot
if(false == Logging::Instance().addAppender(m_pFileLogAppender))
{

}

}



The strange thing is ClientLogging is also a singleton, the first one
that is called, and this works fine.
This is called using:

ClientLogging::Instance().initClientErrorLog(install);

But it is inside this that the problems arise, on the line as seen
above

string szLogLevel =
ConfigManager::Instance().getConfigMgrValue("LOG_LEVEL");

The code just terminates.


Is there anything I can do to prevent this, any pragma.
Could this be because I initialize static variables.

We can't tell from the little code you've shown. I'd suspect that the
problem has to do with how you're using or configuring the service (e.g.,
permissions, as Doug suggests). It could also have to do with the order of
initialization of static variables, but you haven't shown those variables or
how they're initialized.

I'd suggest you ask in a windows newsgroup with any windows-related
questions.

But if you think this is really a C++ _language_ question, you could try to
temporarily change the code so that your functions don't do anything
specific to Windows, and see if you still get the same behavior. Then post
the code (with the static variables involved and how they're initialized)
here and we can help see if it's a language-related issue.

-Howard
 
P

Phil Wilson

It could also be a service dependency thing. Your service could be dependent
on (say) the RPC service, but if you haven't installed it that way it will
come up first and fail. Of course those other dependent services are
already running when you start yours manually later.
 
A

Axter

Hi,

I am writing a windows service. The code runs fine when I start the
service when my machine is running but
it fails to start automatically when the machine reboots. The code
bombs out when it reaches code that tries to access
a singleton class. This is the code.



void ClientLogging::initClientErrorLog(InstallationInfo install)
{

// next line fails on a reboot
string szLogLevel =
ConfigManager::Instance().getConfigMgrValue("LOG_LEVEL");

Logging::Instance().Initialize("IseeCltLog");

Logging::LogLevel severity =
Logging::Instance().toSeverity(szLogLevel);

m_pFileLogAppender = new FileLogAppender(severity, logFile); //this
line fails on reboot
if(false == Logging::Instance().addAppender(m_pFileLogAppender))
{

}

}



The strange thing is ClientLogging is also a singleton, the first one
that is called, and this works fine.
This is called using:

ClientLogging::Instance().initClientErrorLog(install);

But it is inside this that the problems arise, on the line as seen
above

string szLogLevel =
ConfigManager::Instance().getConfigMgrValue("LOG_LEVEL");

The code just terminates.


Is there anything I can do to prevent this, any pragma.
Could this be because I initialize static variables.


Your help would be greatly appreciated.

Your singletons should be created inside a static member function as a
local static variable.
That's the only way to garantee, that your singleton will be created in
a just-in-time order.
If you create your singleton as a global variable or a static member
variable, there's no way to garantee it will be initialized when it's
first used by another global object (like another singleton).
Example:
foo& foo::Instance() //Where Instance is declared as a static method
{
static foo my_foo;
return my_foo;
}
 
G

Guest

Hi,

Thanks for all your replies.

I do think it is a singleton issue.

When I comment out the code above the service starts correctly. The
service is already dependent on the RPC service. I have been through a
microsoft support case to verify this.

But I would like to hear more about the last reply from Axter.

This is my current Instance() function.

Foo& Foo::Instance(void)
{
if(_theInstance == 0)
_theInstance = new Foo();
return *_theInstance;
}

How do I change this to incorporate your last advice.


Enda
 
A

Alf P. Steinbach

* (e-mail address removed):
> [top-posting, over-quoting, cross-posting to Windows group]

Please don't top-post in [clc++]; please don't quote irrelevant
material; please don't cross-post post to platform-specific groups.

And please read the [clc++] FAQ before posting to [clc++].

The FAQ has a section about how to post.
 
G

Guest

Alf said:
* (e-mail address removed):
[top-posting, over-quoting, cross-posting to Windows group]

Please don't top-post in [clc++]; please don't quote irrelevant
material; please don't cross-post post to platform-specific groups.

And please read the [clc++] FAQ before posting to [clc++].

The FAQ has a section about how to post.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?


Ok,


Sorry about that,

but can someone explain to me how to implement this Just in time
singleton based on my current instance function.

Foo& Foo::Instance(void)
{
if(_theInstance == 0)
_theInstance = new Foo();
return *_theInstance;
}



Enda
 
M

mlimber

can someone explain to me how to implement this Just in time
singleton based on my current instance function.

Foo& Foo::Instance(void)
{
if(_theInstance == 0)
_theInstance = new Foo();
return *_theInstance;
}

Well, we can't see the rest of your code, but here's a more complete
example:

template<class T>
class Singleton
{
public:
static T& Instance();
private:
// Disabled functions
Singleton();
Singleton( const Singleton& );
Singleton& operator=( const Singleton& );
Singleton* operator&();
~Singleton();
};

template<class T>
T& Singleton<T>::Instance()
{
static T myObject;
return myObject;
}

Which is used as a wrapper like this:

class A
{
public:
void DoSomething();
// ...

private:
// Private constructor/destructor disallows creation
// except by friends.
friend class Singleton<A>;
A();
~A();

// Disabled functions for singleton usage
A( const A& );
A& operator=( const A& );
A* operator&();
};

typedef Singleton<A> theA;

void Foo()
{
theA::Instance().DoSomething();
}

See chapter 6 of _Modern C++ Design_ for more than you ever wanted to
know about templates in C++.

Cheers! --M
 
M

mlimber

mlimber said:
See chapter 6 of _Modern C++ Design_ for more than you ever wanted to
know about templates in C++.

^^^^^^^^^

I meant "singletons" not "templates" (although, the latter might also
apply). --M
 
D

Doug

Hi,

Thanks for all your replies.

I do think it is a singleton issue.

When I comment out the code above the service starts correctly.

But that could be because both the lines you identify as failing
involve file access.

How about this: try commenting out the body of
ClientLogging::initClientErrorLog() except for a call to
ConfigManager::Instance(), and then comment out any file access code
inside the ctor for ConfigManager.

I'd wager that this will run fine, and both your singletons will be
created just as you expect. (Of course, without your ConfigManager
initialised properly, your program will probably fail to do what it's
supposed to - but it will show you if file access is the issue.)

The method you show of initialising a singleton is probably fine. It's
a lazy method (where no instance will be created if never required),
but in a multithreaded environment this is hard to do efficiently
without locking.

The method of using a static (although it is better if this is a static
class member, rather than a function local static) works (and is
efficient - requiring no locking), but is not lazy and is obviously
only possible if the resources required to create it are available at
runtime (when such globals are usually initialised). (This is also the
situation in which you can get yourself into dependency problems -
which you originally thought [and I guess, still think] you had.)

HTH,
Doug
 
G

Guest

mlimber said:
^^^^^^^^^

I meant "singletons" not "templates" (although, the latter might also
apply). --M


Thanks, I will try it out.

But this is the singleton template I was using, do you see any issues
why this would not start when the machine reboots.


class DLLEXPORT CSingleton
{
public:

// Return A reference to the instance of the CSingleton class.
// If there is no instance of the class yet, one will be created.
static T& Instance()
{
if (m_instance == 0 )
{
if (m_instance == 0)
{
m_instance = new T;

// exit processing function
std::atexit(CSingleton::DestroyInstance);
}
}
return *(CSingleton::m_instance);
};

// Destroys the CSingleton class instance.
// Be aware that all references to the single class instance will be
// invalid after this method has been executed!
static void DestroyInstance()
{
delete m_instance;
m_instance = NULL;
};

protected:

// shield the constructor and destructor to prevent outside sources
// from creating or destroying a CCSingleton instance.

inline explicit CSingleton() { CSingleton::m_instance =
static_cast<T*>(this); }
inline ~CSingleton() { CSingleton::m_instance = 0; }

private:

inline explicit CSingleton(CSingleton const&) {}
inline CSingleton& operator=(CSingleton const&) { return *this; }

private:

static T* m_instance; // CSingleton class instance
};

// static class member initialisation.
//template <typename T> T* CSingleton<T>::m_instance = 0;



~Enda
 
D

Doug

Thanks, I will try it out.

But this is the singleton template I was using, do you see any issues
why this would not start when the machine reboots.


class DLLEXPORT CSingleton
{
public:

// Return A reference to the instance of the CSingleton class.
// If there is no instance of the class yet, one will be created.
static T& Instance()
{
if (m_instance == 0 )
{
if (m_instance == 0)
{
m_instance = new T;

// exit processing function
std::atexit(CSingleton::DestroyInstance);
}
}
return *(CSingleton::m_instance);
};

// Destroys the CSingleton class instance.
// Be aware that all references to the single class instance will be
// invalid after this method has been executed!
static void DestroyInstance()
{
delete m_instance;
m_instance = NULL;
};

protected:

// shield the constructor and destructor to prevent outside sources
// from creating or destroying a CCSingleton instance.

inline explicit CSingleton() { CSingleton::m_instance =
static_cast<T*>(this); }
inline ~CSingleton() { CSingleton::m_instance = 0; }

private:

inline explicit CSingleton(CSingleton const&) {}
inline CSingleton& operator=(CSingleton const&) { return *this; }

private:

static T* m_instance; // CSingleton class instance
};

// static class member initialisation.
//template <typename T> T* CSingleton<T>::m_instance = 0;



~Enda

Hiya,

Other than the odd double-if test around mInstance (which won't help
with locking, if that's what it's for), I can't see any reason why this
would give you any problems.

Doug
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top