首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++中异步线程安全日志记录(无互斥锁)

C++中异步线程安全日志记录(无互斥锁)
EN

Stack Overflow用户
提问于 2011-11-16 18:36:24
回答 6查看 8.8K关注 0票数 8

实际上,我正在寻找一种在我的C++中进行异步和线程安全日志记录的方法。

我已经探索过线程安全的日志记录解决方案,如log4cpp、log4cxx、Boost:log或rlog,但它们似乎都使用了互斥锁。据我所知,互斥是一种同步解决方案,这意味着所有线程在尝试写入消息时都会被锁定,而其他线程则会这样做。

你知道解决方案吗?

EN

回答 6

Stack Overflow用户

发布于 2011-11-16 19:19:30

我认为你的说法是错误的:使用互斥不一定等同于同步解决方案。是的,Mutex是用于同步控制的,但它可以用于许多不同的事情。例如,我们可以在生产者、消费者队列中使用互斥锁,同时日志记录仍在异步进行。

老实说,我没有研究过这些日志库的实现,但是应该可以创建一个异步附加器(对于像lib这样的log4j ),记录器写入生产者消费者队列,而另一个工作线程负责写入文件(甚至委托给另一个附加器),以防它没有提供。

编辑:刚刚在log4cxx中做了一个简单的扫描,它提供了一个AsyncAppender,它做了我建议的事情:缓冲传入的日志事件,并异步委托给附加的附加器。

票数 6
EN

Stack Overflow用户

发布于 2011-11-16 19:04:03

我会重新注释,通过只使用一个线程来记录日志来避免这个问题。为了将必要的数据传递到日志,可以使用无锁fifo队列(只要生产者和消费者严格分离,并且每个角色只有一个线程,那么线程就是安全的--因此,每个生产者需要一个队列。)

快速解锁队列示例如下:

queue.h e.h:

代码语言:javascript
运行
复制
#ifndef QUEUE_H
#define QUEUE_H

template<typename T> class Queue
{
public:
    virtual void Enqueue(const T &element) = 0;
    virtual T Dequeue() = 0;
    virtual bool Empty() = 0;
};

杂交队列.h:

代码语言:javascript
运行
复制
#ifndef HYBRIDQUEUE_H
#define HYBRIDQUEUE_H

#include "queue.h"


template <typename T, int size> class HybridQueue : public Queue<T>
{

public:
    virtual bool Empty();
    virtual T Dequeue();
    virtual void Enqueue(const T& element);
    HybridQueue();
    virtual ~HybridQueue();

private:
    struct ItemList
    {
        int start;
        T list[size];
        int end;
        ItemList volatile * volatile next;
    };

    ItemList volatile * volatile start;
    char filler[256];
    ItemList volatile * volatile end;
};

/**
 * Implementation
 * 
 */

#include <stdio.h>

template <typename T, int size> bool HybridQueue<T, size>::Empty()
{
    return (this->start == this->end) && (this->start->start == this->start->end);
}

template <typename T, int size> T HybridQueue<T, size>::Dequeue()
{
    if(this->Empty())
    {
        return NULL;
    }
    if(this->start->start >= size)
    {
        ItemList volatile * volatile old;
        old = this->start;
        this->start = this->start->next;
            delete old;
    }
    T tmp;
    tmp = this->start->list[this->start->start];
    this->start->start++;
    return tmp;
}

template <typename T, int size> void HybridQueue<T, size>::Enqueue(const T& element)
{
    if(this->end->end >= size) {
        this->end->next = new ItemList();
        this->end->next->start = 0;
        this->end->next->list[0] = element;
        this->end->next->end = 1;
        this->end = this->end->next;
    }
    else
    {
        this->end->list[this->end->end] = element;
        this->end->end++;
    }
}

template <typename T, int size> HybridQueue<T, size>::HybridQueue()
{
    this->start = this->end = new ItemList();
    this->start->start = this->start->end = 0;
}

template <typename T, int size> HybridQueue<T, size>::~HybridQueue()
{

}

#endif // HYBRIDQUEUE_H
票数 5
EN

Stack Overflow用户

发布于 2011-11-16 19:08:31

如果我没有弄错您的问题,那么您关心的是在记录器的临界区中执行I/O操作(可能是写入文件)。

Boost:log可以让你定义一个自定义的编写器对象。您可以定义操作符()来调用异步I/O或将消息传递到日志记录线程(正在执行I/O)。

http://www.torjo.com/log2/doc/html/workflow.html#workflow_2b

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8150249

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档