首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++缓冲池?

C++缓冲池?
EN

Stack Overflow用户
提问于 2012-04-06 03:31:11
回答 3查看 4.6K关注 0票数 2

我有一个强大的用例,可以预先分配我需要的所有内存,并在完成后释放它。

我已经提出了这个真正简单的缓冲池C++实现,我必须对其进行测试,但我不确定我尝试使用的指针算法是否允许我这样做。基本上就是我下一步做并发布的部分。我更喜欢围绕这个想法的一些技巧,而不是依赖于任何类型的内存处理程序,这只会使客户端代码更加复杂。

代码语言:javascript
复制
#include <stdio.h>
#include <queue>

#include "utils_mem.h"

using namespace std;

template <class T>
class tbufferpool {
private:
    const int m_initial;
    const int m_size;
    const int m_total;
    T*        m_buffer;
    vector<T*> m_queue;

public:
    // constructor
    tbufferpool(int initial, int size) : m_initial(initial), m_size(size), m_total(initial*size*sizeof(T)) {
        m_buffer = (T*) malloc(m_total);
        T* next_buffer = m_buffer;
        for (int i=0; i < initial; ++i, next_buffer += i*size) {
            m_queue.push_back(next_buffer);
        }
    }

    // get next buffer element from the pool
    T* next() {
        // check for pool overflow
        if (m_queue.empty()) {
            printf("Illegal bufferpool state, our bufferpool has %d buffers only.", m_initial);
            exit(EXIT_FAILURE);
        }
        T* next_buffer = m_queue.back();
        m_queue.pop_back(); 
        return next_buffer;
    }

    // release element, make it available back in the pool
    void release(T* buffer) {
        assert(m_buffer <= buffer && buffer < (buffer + m_total/sizeof(T)));
        m_queue.push_back(buffer);
    }

    void ensure_size(int size) {
        if (size >= m_size) {
            printf("Illegal bufferpool state, maximum buffer size is %d.", m_size);
            exit(EXIT_FAILURE);
        }
    }

    // destructor
    virtual ~tbufferpool() {
        free(m_buffer);
    }
};
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-04-06 03:55:17

首先,当您增加指向T的指针时,它将指向内存中T的下一个元素。

代码语言:javascript
复制
m_queue.push(m_buffer + (i*size*sizeof(T)));

这应该是这样的

代码语言:javascript
复制
m_buffer = (T*) malloc(m_total);
T* next = m_buffer;
for (int i=0; i < initial; ++i) {
    m_queue.push(next++);
}

第二,

代码语言:javascript
复制
assert(m_buffer <= buffer && buffer < m_total);

它应该是这样的

代码语言:javascript
复制
assert(m_buffer <= buffer && buffer <= m_buffer + m_total/sizeof(T));

希望它能帮上忙!

票数 1
EN

Stack Overflow用户

发布于 2012-04-06 03:59:40

我不明白为什么要“包装”STL queue<>容器。只需将您的“缓冲区”放入队列中,并在需要时提取地址即可。当你处理完缓冲区中的“段”时,只需将它从队列中弹出,它就会自动释放。因此,不是指向缓冲区的指针,而是实际的buffer类。

这让我觉得这是在重新发明轮子。现在,由于您需要一次分配所有内容,我将使用vector而不是queue,因为vector<>类型可以在构造时一次性分配,并且push_back()方法不会重新分配,除非需要,pop_back()也是如此。有关使用的方法,请参阅here

不过,基本上,这是我的粗略想法:

代码语言:javascript
复制
#include <myType.h> // Defines BufferType

const int NUMBUFFERS = 30;

int main()
{
    vector<BufferType> myBuffers(NUMBUFFERS);
    BufferType* segment = &(myBuffers[0]);    // Gets first segment
    myBuffers.pop_back(); // Reduces size by one

    return 0;
}

我希望这能给你一个大概的概念。你可以这样使用向量中的缓冲区,并且只有一个分配或释放,如果你愿意,你可以使用类似堆栈的逻辑。dequeue类型或其他标准容器可能也值得一看,但如果只是“我只想要一个分配或释放”,我会使用向量,甚至可能使用指向数组的智能指针。

票数 1
EN

Stack Overflow用户

发布于 2012-04-06 07:37:02

我在使用对象池时发现了一些东西:

我不确定是否可以一次分配所有对象。我喜欢从一个'pooledObject‘类中继承我所有的池化对象,这个类包含一个对它自己的池的私有引用,所以允许一个简单的,无参数的'release’方法,并且我总是绝对确定一个对象总是被释放回它自己的池。我不确定如何使用静态数组ctor加载具有池引用的每个实例-我总是在循环中一个接一个地构造对象。

另一个有用的私有成员是一个“已分配的”布尔值,当一个对象被放入池中并在释放时被清除时,它就会被设置。这允许pool类检测,除非一个对象被释放两次。“发布两次”错误如果不能立即被检测到,可能会非常糟糕--奇怪的行为或崩溃会在几分钟后发生,而且通常发生在另一个模块的另一个线程中。最好尽快检测到双倍释放!

我发现在1秒计时器上将我的池的级别转储到状态栏中是有用的,也是令人放心的。如果发生泄漏,我可以看到它的发生,并且,通常,当一个数字惊人地下降时,通过我所在的活动来了解泄漏在哪里。谁需要Valgrind:)

在线程方面,如果您必须使您的池是线程安全的,那么使用阻塞队列会很有帮助。如果池耗尽,尝试获取对象的线程可以等待,直到它们被释放,应用程序只会减慢速度,而不是崩溃/死锁。另外,要小心re。虚假分享。您可能必须使用“填充”数组数据成员来确保没有两个对象共享一个缓存线。

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

https://stackoverflow.com/questions/10034839

复制
相关文章

相似问题

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