多线程记录器在一段时间后崩溃,我找不到解决问题的方法

时间:2019-05-06 16:00:15

标签: multithreading c++11 logging cross-platform

简介

我正在使用多线程跨平台日志记录工具,该工具旨在记录到控制台和/或文件中。但是,我现在遇到的问题仅与控制台日志记录有关。

问题细分

记录器的工作方式是将字符串添加到字符串队列中。在“ LogToConsole”线程中,有一个wait方法,该方法等待直到队列中添加了字符串。发生这种情况时,它应该得到通知并打印,然后弹出并解锁。

使用的变量

    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;
                ...

我将数据添加到缓冲区的位置

    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);
    }

在单独的循环中运行的线程(但是请注意,该方法不属于logger类的一部分):


    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());
    }

线程创建的地方

    Logger::Logger() : _LogThread(), _LogBuffer(), _ThreadName(), _LogMutex()
    {
        _ThreadIsRunning.test_and_set();
        _LogThread = std::thread(LogToConsole, this);
    }

测试框

        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");
        }

该代码似乎是线程安全的,没有数据争用等,但是它会在5-10秒后崩溃。我已经搜索过是否有人遇到类似的问题,但事实并非如此。

The exception that gets thrown after 10 seconds

但是我对并发编程不是很有经验,因此现在不要很轻松地处理这类问题。

希望有人可以解决问题或给我一些建议以防止出现问题。

1 个答案:

答案 0 :(得分:0)

while (logger->_ThreadIsRunning.test_and_set() || !logger->_LogBuffer.empty());中,您无需互斥就访问logger,所以这是一场数据竞赛。另外,_LogBuffer.push(log.str());只能在_AppendLock锁定的情况下访问,而logger->_LogBuffer.pop()只能在_LogMutex锁定的情况下访问,所以这是另一种数据竞争。

数据争用是UB,也是崩溃的可能原因。