C++ C+中的线程安全日志缓冲区+;?

C++ C+中的线程安全日志缓冲区+;?,c++,C++,为了提高性能,我正在实现自己的日志系统(因为我基本上只需要一个缓冲区)。我现在拥有的是这样的东西: // category => messages static std::unordered_map<std::string, std::ostringstream> log; void main() { while (true) { log["info"] << "Whatever"; log["192.168.0.1"] &

为了提高性能,我正在实现自己的日志系统(因为我基本上只需要一个缓冲区)。我现在拥有的是这样的东西:

// category => messages
static std::unordered_map<std::string, std::ostringstream> log;

void main() {
    while (true) {
        log["info"] << "Whatever";
        log["192.168.0.1"] << "This is a dynamic entry";

        dump_logs();
    }
}

void dump_logs() {
    // i do something like this for each category, but they have different save strategies
    if (log["info"].tellp() > 1000000) {
        // save the ostringstream to a file

        // clear the log
        log["info"].str("")
    }
}
//类别=>消息
静态std::无序映射日志;
void main(){
while(true){

log[“info”]您可以通过声明map
thread\u local
使此线程安全。如果要跨翻译单元使用它,请将其设置为
extern
并在一个翻译单元中定义,否则
静态
就可以了

您仍需要同步将日志写入磁盘。互斥锁应解决以下问题:

// category => messages (one per thread)
thread_local static std::unordered_map<std::string, std::ostringstream> log;

void main() {
    while (true) {
        log["info"] << "Whatever";
        log["192.168.0.1"] << "This is a dynamic entry";

        dump_logs();
    }
}

void dump_logs() {

    static std::mutex mtx; // mutex shared between threads

    // i do something like this for each category, but they have different save strategies
    if (log["info"].tellp() > 1000000) {

        // now I need to care about threads
        // use { to create a lock that will release at the end }
        {
            std::lock_guard<std::mutex> lock(mtx); // synchronized access

            // save the ostringstream to a file
        }

        // clear the log
        log["info"].str("");
    }
}
//category=>消息(每个线程一条)
线程\u本地静态std::无序\u映射日志;
void main(){
while(true){

日志[“info”]在POSIX系统上,如果您总是将数据写入文件末尾,多线程将数据写入文件的最快方式是在追加模式下使用低级C样式
open()
,只需调用
write()
,因为以下状态:

在常规文件或其他能够查找的文件上,实际写入 数据的保存应从文件中的以下位置开始: 与fildes关联的文件偏移量。从成功返回之前 write(),文件偏移量应增加字节数 实际写入。在常规文件中,如果最后一个字节的位置 Write大于或等于文件的长度,即 文件的位置应设置为该位置加1

如果设置了文件状态标志的O_APPEND标志,则文件偏移量 应在每次写入之前设置为文件末尾,且 文件修改操作应在更改之间进行 文件偏移量和写入操作

因此,进程内对以追加模式打开的文件的所有
write()
调用都是原子的

不需要互斥体

差不多了。你唯一要关心的是

如果成功写入后,
write()
被信号中断 对于某些数据,它应返回写入的字节数


如果您对环境有足够的控制权,可以确保对
write()的调用
在仅写入部分数据后不会被信号中断,这是从多个线程将数据写入文件的最快方法-您在文件描述符上使用操作系统提供的锁,确保遵守POSIX指定的行为,只要生成要写入的数据而不加任何锁定,就可以t文件描述符锁是整个数据路径中唯一的一个。无论您在代码中执行什么操作,该锁都将位于您的数据路径中。

您“只需要一个缓冲区”做了什么?在我看来,执行映射查找每个日志调用都不是很有效。不,它不是线程安全的。映射查找不是线程安全的,ostringstream写入也不是线程安全的。这些代码不是线程安全的。如果您对线程安全日志系统的外观感兴趣,我在我的配置文件中定制了一个,您可以自由使用根据您的意愿使用和操作。我需要类别来分离缓冲区卸载策略。类别是动态的。这就是为什么我需要映射查找。您可以在对日志执行操作时使用互斥体,以确保日志一次使用的线程数不超过1个。即使创建一个类,也不必每次都创建互斥体时间会更好。这不是一个日志库。这是一个非常具体问题的非常具体的解决方案。我不想超越任何人,我真的不理解这里的态度。我有一个简短的问题,这有点相关,既然你帮了我很多忙,你可能也知道这个问题的答案!我如何解决这个问题缓冲区剩余数?如果日志中剩余的字节少于1000000字节,它们将不会被保存。我刚刚意识到这一点:(@vinnylinux)您可以使用类似的函数,名为
close_logs()
这在没有检查的情况下做同样的事情,所以它总是清空缓冲区。或者你可以将整个事情包装在一个类中,在析构函数中做一些事情。是的,但我处于一个while true循环中,因为这是一个守护进程。我首先想到的是一个线程,专门在周期内运行,比如cron,以卸载缓冲区。@vinnylinux虽然不知道整个情况,但很难想出主意。我猜你想在守护进程关闭/重新启动时保存日志?捕获kill信号怎么样?不是真的。我只是发现保存日志(一些到磁盘,其他到MySQL,其他通过webhook发送,等等)价格越来越贵,所以我决定制作一个缓冲区,并将它们分块发送。