首页 > 解决方案 > 如何实现线程安全的日志记录?

问题描述

我在这里实现了一个 Logging 类。

class Log : public std::streambuf, public std::ostream {
  public:
    Log(int severity, const char* func, int line) :
        std::ostream(this), severity_(severity) {
        (this->severity_ == ERROR) ? std::cout << RED << "ERROR " :
                                     std::cout << RESET << "INFO ";
        std::cout << func << " @ line# " << line << ": ";
    }
    int overflow(int c) {
        if (this->severity_ == ERROR) {
            std::cout << RED;
            std::cout.put((char) c);
        } else {
            std::cout.put((char) c);
        }
        return 0;
    }
    ~Log() {
        std::cout << RESET << std::endl;
    }
    
  private:
    int severity_;
};

这工作正常。但是当两个线程同时执行时,输出有时会混合在一起。我经历了几个 SO 问题,但他们都以更广泛的方式讨论了这个问题。我有这个我想修复的特定实现。我尝试添加一个全局互斥锁并以线程安全的方式调用它,但问题是该文件是一个全局头文件,因此不能在此处全局定义互斥锁变量,因为它会导致多个定义错误。有没有什么办法解决这一问题?

标签: c++multithreadinglogging

解决方案


我前段时间做过类似的事情。我的解决方案是添加一个成员互斥锁(m_queue_mutex在示例中)来控制对存储要记录的字符串的成员队列的访问,使用类似的函数将字符串排入队列

void print_log(std::string& msg)
{
    // Format the message here, maybe add some severity tag and line numbers
    // Lock the mutex, maybe something like
    //     std::lock_guard<mutex_type> queue_lock{m_queue_mutex};
    // Now enqueue the formatted string into the mutex
}

m_queue_mutex防止同时访问记录器队列,因此在从队列中获取字符串进行输出时也要锁定它

我的记录器还有一个线程定期锁定队列并将内容输出到文件。这种日志记录线程方法对调用记录器的线程的影响最小,因为它消除了另一个线程的 i/o 负担。我将它用于需要良好性能的服务器守护程序应用程序。


推荐阅读