【问题标题】:How to implement a thread safe logging?如何实现线程安全的日志记录?
【发布时间】:2020-12-29 14:38:22
【问题描述】:

我在这里实现了一个 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 问题,但他们都以更广泛的方式讨论了这个问题。我有这个我想修复的特定实现。我尝试添加一个全局互斥锁并以线程安全的方式调用它,但问题是该文件是一个全局头文件,因此不能在此处全局定义互斥锁变量,因为它会导致多个定义错误。有没有办法解决这个问题?

【问题讨论】:

  • 全局变量最终会帮助你。最好是static member variable,这样所有记录器都共享一个记录器范围的互斥锁。
  • 旁注:要解决全局互斥锁(可能只是众多互斥锁中的第一个)问题,请阅读How do I use extern to share variables between source files?
  • 如果您在多个线程中使用一个Log 对象,则使用该对象的代码将负责同步对该对象的访问(创建一个互斥体,在使用Log 之前获取它,释放完成后等)。如果你想要多个Log对象都写入一个公共流,Log类需要设置单个互斥体(例如作为类的静态成员),并且所有成员函数都需要在写入之前抓取互斥体到流,并在完成对流的操作后释放互斥锁。流本身可能也需要是静态类成员。

标签: c++ multithreading logging


【解决方案1】:

我前段时间做过类似的事情。 我的解决方案是添加一个成员互斥锁(示例中为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防止同时访问logger队列,所以在从队列中取出字符串输出时也要加锁

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

【讨论】:

  • 队列和 m_queue_mutex 是全局的吗?否则会有多个实例,结果是一样的。
  • 不,他们是会员。我将添加说明。我的意思是允许使用多个记录器对象,因此没有全局变量。
  • 我想我没听懂你之前说的话。如果您想要一个全局记录器,只需创建记录器类的全局对象,或者将其用作单例的成员。并处理我在答案中发布的所有线程的日志记录(使用互斥锁或其他东西)。我以为你已经完成了那部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多