c++ - 如何创建支持 `<<` 操作的线程安全日志类?

标签 c++ multithreading logging boost boost-thread

所以我有这样的日志类:

#include <iostream>
#include <sstream>
#include <boost/circular_buffer.hpp>
#include <boost/foreach.hpp>

class FlushInternal;

class Log
{
public:

    static FlushInternal* endl;

    Log(int log_length)
    {
        i = 0;
        messages_buffer = new boost::circular_buffer<std::string>(log_length);
    }

    template <class T>
    Log &operator<<(const T &v)
    {
        current_message << v;
        return *this;
    }

    Log &operator<<(std::ostream&(*f)(std::ostream&)) 
    {
        current_message << *f;
        return *this;
    }

    Log &operator<<(FlushInternal*)
    {
        ++i;
        messages_buffer->push_back(current_message.str());
        clean_stringstream(current_message);
        is_filled();
        return *this;
    }

    boost::circular_buffer<std::string> *messages_buffer;

private:
    int i;
    std::stringstream current_message;

    void is_filled()
    {
        if (i >= messages_buffer->capacity())
        {
            i = 0;
            BOOST_FOREACH(std::string s, *messages_buffer)
            {
                std::cout << ++i << ": "  << s << " ;" << std::endl;
            } 
            i = 0;
        }
    }

    void clean_stringstream(std::stringstream &message)
    {
        message.flush();
        message.clear();
        message.seekp(0);
        message.str("");
    }
};

FlushInternal* Log::endl = 0;

我可以这样使用它:

#include <log.h>
int main()
{
    Log l(2);
    l << "message one: " << 1 << Log::endl;
    l << "message two:" << " " << 2 << Log::endl;
    l << "message " << "three: " << 3 << Log::endl;
    l << "message" << " "  << "four: " << 4 << Log::endl;
    std::cin.get();
}

这将输出:

1: message one: 1 ;
2: message two: 2 ;
1: message three: 3 ;
2: message four: 4 ;

如你所见,我可以拥有尽可能多的<<正如我在每条日志消息中所希望的那样。我希望能够使用 Log 的一个实例同时来自多个线程的类。所以我会有类似的东西(编译、运行但什么都不跟踪的伪代码。):

#include <boost/thread.hpp>
#include <log.h>

Log *l;

void fun_one()
{
    *l << "message one: " << 1 << Log::endl;
    *l << "message two:" << " " << 2 << Log::endl;
}

void fun_two()
{
    *l << "message " << "three: " << 3 << Log::endl;
    *l << "message" << " "  << "four: " << 4 << Log::endl;
}

int main()
{
    l = new Log(2);
    boost::thread(fun_one);
    boost::thread(fun_two);
    std::cin.get();
}

如您所见,我希望在多线程函数中将消息插入到日志中。 Lo 我想知道 - 如何让我的日志 cclass 支持这个?

最佳答案

trojanfoe 链接的方法几乎是规范的方法。基本上为最左边的 << 运算符创建一些临时的东西,积累所有东西,并在临时东西的析构函数中输出消息。

唯一的问题是这个累加器的确切机制。该示例使用了 ostringstream,但我也看到了直接使用日志文件的 ofstream(需要锁定以确保输出在一行结束)。

创建 ostringstreams 在某些平台上相对昂贵,因为它们可能需要锁定和复制一些与内部语言环境相关的东西。您还可以为有趣的类型重新实现 << 运算符,但我会先测试 ostringstream 方法。

有用的优化是在构建临时文件时确定是否将发出跟踪(例如,是否在该特定级别启用跟踪),并且在这种情况下根本不创建临时文件的内容 -所有插入操作都是空操作。

关于c++ - 如何创建支持 `<<` 操作的线程安全日志类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7118034/

相关文章:

c++ - 如何将 bitset 转换为字节数组/uint8?

java - 我可以将 PriorityBlockingQueue 与多个线程一起使用吗?

java - Log4j 隐式字符串格式化

c++ - Poco Logger 更改 Message 参数

java - 使用 Java 中的 Logger 库登录文件时出现问题

c++ - 变量的常量及其生命周期

c++ - 函数调用中的 free struct 参数过多

c++ - GoogleTest Framework 似乎不适用于 Lambda 函数(跟进)

android - 服务 vs IntentService 在位置跟踪服务的情况下

java - Java中父子线程的通信