Intro:
I am working on a multithreaded cross platform logging tool which purposes logging to the console and/or a file. However the problem I have right now is only related to the console logging.
Problem breakdown:
The way the logger works is by adding a string to a Queue of strings. In the "LogToConsole" thread there is a wait method that waits until there is a string added to the queue. When that happens it should get notified and print, then pop and unlock.
Used variables:
class Logger
{
public:
friend void LogToConsole(Logger* logger);
private:
std::atomic_flag _ThreadIsRunning { ATOMIC_FLAG_INIT };
std::thread _LogThread;
std::queue<std::string> _LogBuffer;
std::map<std::thread::id, std::string> _ThreadName;
std::mutex _LogMutex;
std::mutex _AppendLock;
std::condition_variable _LogLock;
...
The place I add data to the buffer:
template<LogSeverity severity>
void Logger::Log(std::stringstream& message)
{
std::stringstream log;
log << _ThreadName[std::this_thread::get_id()] << ":\t";
log << message.str();
std::unique_lock<std::mutex> logAppendLock(_AppendLock);
_LogBuffer.push(log.str());
logAppendLock.unlock();
_LogLock.notify_one();
}
template<LogSeverity severity>
void Logger::Log(std::string message)
{
std::stringstream log;
log << message.c_str();
this->Log<severity>(log);
}
The thread that runs in a seperate loop (notice however that this method is not part of the logger class):
void LogToConsole(Logger* logger)
{
do
{
std::unique_lock<std::mutex> lock(logger->_LogMutex);
logger->_LogLock.wait(lock);
std::printf("%s", logger->_LogBuffer.back().c_str());
logger->_LogBuffer.pop();
lock.unlock();
} while (logger->_ThreadIsRunning.test_and_set() || !logger->_LogBuffer.empty());
}
Place of thread creation:
Logger::Logger() : _LogThread(), _LogBuffer(), _ThreadName(), _LogMutex()
{
_ThreadIsRunning.test_and_set();
_LogThread = std::thread(LogToConsole, this);
}
Test casing:
std::shared_ptr<Logger> engineLogger = std::make_shared<Logger>();
engineLogger->SetThreadName("EngineLogger");
std::shared_ptr<Logger> coreLogger = std::make_shared<Logger>();
coreLogger->SetThreadName("CoreLogger");
while(true)
{
engineLogger->Log<LOG_INFO>("LOG\n");
coreLogger->Log<LOG_WARNING>("WARNING\n");
}
The code seems to be working threadsafe, no dataraces etc. but it crashes after a 5-10~ seconds. I have searched if there are people that are having a similar problem, this does not seem to be the case.
The exception that gets thrown after 10 seconds
I am however not very experienced with concurrent programming, thus do not now how to handle these kind of problems very easily.
Hope someone can solve the problem or give me some advice to prevent the problem.
Cheers, Tom
Aucun commentaire:
Enregistrer un commentaire