Reputation: 36217
I am currently learning C++ and I am having an odd issue with threads. I've done lots of threaded stuff in Java and C# and not had an issue. I am currently trying to replicate a C# library that I have in C++ with a library and a test app.
In main.cpp I create an instance of a InitialiseLibrary
class and call the method initialise
. This does config loading and is then supposed to start a thread which stays running through the duration the application is running. I am expecting this thread to start, and then my initialise function returns true where I then continue and I create an instance of a test class which writes to a log file every 1 second.
Below is main.cpp
InitialiseLibrary initLibrary("config.ini");
if (!initLibrary.initialise(1))
{
cout << "Failed to initialise library" << endl;
return EXIT_FAILURE;
}
TestClass testClass;
testClass.writeSomeLogsInThread();
cout << "The library config log file is: " << GlobalConfig::GeneralConfig::logFile << endl;
In my Initialise method (which is in the library) I have:
bool InitialiseLibrary::initialise(int applicationAlarmID, int applicationTerminationTimeout)
{
//statusManager.setApplicationStatus(StatusManager::ApplicationStatus::Starting);
if (!this->loadInconfiguration(applicationAlarmID))
{
cout << "*****Failed to configuration. Cannot continue******" << endl;
return false;
}
GlobalConfig::libraryInitialised = true;
LogRotation logRotation;
logRotation.startLogRotation();
BitsLibrary bitsLibrary;
//Set up the signal handler if its needed, 0 means it terminates instantly, doesn't wait -1 is don't use signal handler
if (applicationTerminationTimeout >= 0)
{
bitsLibrary.setupSignalHandler(applicationTerminationTimeout);
}
return true;
}
As you can see, I read in the configuration and I then call `logRotation.startLogRotation().
Where I have the following code:
void LogRotation::startLogRotation()
{
//Is the configuration successfully loaded
if (!LogRotateConfiguration::configurationLoaded)
{
throw exception("Log Rotation not initialised");
}
BitsLibrary bitsLibrary;
stringstream logStream;
logStream << "Log rotation thread starting, monitor cycle time is " << LogRotateConfiguration::archiveSleepTimeInSeconds << " second(s)";
bitsLibrary.writeToLog(logStream.str(), "LogRotation", "startLogRotation");
thread logRotationThread(&LogRotation::logRotationThread, this);
logRotationThread.join();
}
void LogRotation::logRotationThread()
{
BitsLibrary bitsLibrary;
while (bitsLibrary.getApplicationStatus() == StatusManager::ApplicationStatus::Starting || bitsLibrary.getApplicationStatus() == StatusManager::ApplicationStatus::Running)
{
bitsLibrary.writeToLog("Running log monitoring");
this_thread::sleep_for(chrono::seconds(LogRotateConfiguration::archiveSleepTimeInSeconds));
}
stringstream logStream;
logStream << "Log rotation archive monitoring stopped. Current application status: " << bitsLibrary.getApplicationStatus();
bitsLibrary.writeToLog(logStream.str(), "LogRotation", "logRotationThread");
}
Here I am expecting, startLogRotation()
to start run the method logRotationThread
within a thread, the thread starts, and the startLogrotation() method finishes and backs through the stack to the initialise() method where that returns true, back up to main where I can then call my TestClass method within a thread.
For some reason though, the thread starts and keeps logging every few seconds Running log monitoring
so I know the thread has started, yet it doesn't seem to return back to the initialise function to return true, so the app gets stuck on that function call and doesn't go any further.
I've read that you need to run join
on the thread to keep it in sync with the main thread, otherwise the main thread exits, while the new threads are running and cause a SIGABRT which in deed it does, but having the join there seems to stop the method returning.
Upvotes: 0
Views: 79
Reputation: 3089
From what I can tell,
logRotationThread is a long running thread (it runs for the entire duration of the application). There is no need for the main thread to ever wait (join) on the logRotationThread.
For starters remove logRotationThread.join()
.
Upvotes: 0
Reputation: 66451
join
waits for a thread to finish executing, so when you join, startLogRotation
won't return until that happens.
Also, the normal rules of scope and lifetime apply to thread objects - logRotationThread
will be destroyed when startLogRotation
returns.
If the thread is "joinable" at the time of destruction, it's an error.
The simplest solution is probably to have a LogRotation
member in InitialiseLibrary
and a thread
member in LogRotation
.
You can then join
the thread in LogRotation
's destructor.
Upvotes: 1
Reputation: 8926
Your main thread blocks at this line, waiting for the logRotationThread to end.
logRotationThread.join();
Your main thread should go and do whatever work it needs to do after spawning the other thread, then only when it has nothing left to do should it join()
the log rotate thread.
Upvotes: 1
Reputation: 6993
"having an odd issue with threads" - welcome to the world of threading!
I think you mis-understand the stack of the thread you create, and how it will interact with the main thread. The created thread's stack starts at the function you tell it to start with - when that function completes, the thread dies (which will then allow your join() to stop blocking)
With regards to your communication between threads, I think you should have a read about mutex's, conditions and semaphores.
Upvotes: 0