2012-04-05 50 views
2

我有一個強大的用例來預先分配我需要的所有內存,並在完成時釋放它。C++緩衝池?

我已經出來了這個真正簡單的緩衝池C++實現,我必須測試,但我不確定我正在嘗試使用的指針算法將允許我這樣做。基本上就是我下一步要發佈的位置。我更喜歡這個想法的一些技巧,而不是依賴任何只是使客戶端代碼更復雜的內存處理程序。

#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); 
    } 
}; 
+1

你忘了'pop_back()'... – 2012-04-05 19:33:55

+0

真的,謝謝:) – 2012-04-05 19:41:25

+0

請,請,請永遠不會調用退出類。拋出異常! – devshorts 2012-04-05 19:47:38

回答

1

首先,當你增加一個指向T,它會在內存點T的下一個元素。

m_queue.push(m_buffer + (i*size*sizeof(T))); 

這應該是像

m_buffer = (T*) malloc(m_total); 
T* next = m_buffer; 
for (int i=0; i < initial; ++i) { 
    m_queue.push(next++); 
} 

其次,

assert(m_buffer <= buffer && buffer < m_total); 

應該是這樣

assert(m_buffer <= buffer && buffer <= m_buffer + m_total/sizeof(T)); 

希望它能幫助!

+0

不錯的感謝,我把你的貢獻:) – 2012-04-05 20:08:32

1

我不明白你爲什麼要「包裝」STL隊列容器。只需將您的「緩衝區」放入隊列中,並根據需要提取地址即可。當您在緩衝區中完成「段」時,只需將其從隊列中彈出即可自動釋放。所以,而不是指向緩衝區的指針,你只需要實際的緩衝區類。

它只是讓我重新發明輪子。現在既然你需要一次分配整個東西,我會使用vector不是隊列,因爲vector<>類型可以一次性分配到施工中,並且push_back()方法不會重新分配,除非需要,與之相同pop_back()。有關使用的方法,請參閱here

基本上,雖然,這裏的背的最信封我的想法:

#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類型也許值得一看,或其他標準容器,但如果它只是「我只想要一個分配或解除分配」,我只是使用向量,或者甚至是一個智能指針可能。

+0

相同理由像往常一樣,我想我的抽象客戶端代碼從如何存儲,檢索和保持一致性我的游泳池和不分散這所有的地方所有這些低技術細節了。我需要兩個池實例一個用於矩陣,另一個用於向量開始......我不會在這裏放置一堆隊列代碼,而是使用緩衝池。感謝與矢量的提示。 – 2012-04-05 20:08:00

0

一些東西,我已經找到了使用對象池:

我不知道在一次所有對象分配。我喜歡從包含對其自身池的私有引用的'pooledObject'類下降所有池對象,因此允許一個簡單的,無參數的「釋放」方法,並且我始終確保一個對象始終被釋放回到其對象擁有游泳池。我不確定如何使用靜態數組ctor加載池引用的每個實例 - 我總是在一個循環中逐個構建對象。

另一個有用的私有成員是一個'分配'布爾值,當一個對象被去除和清除時釋放。這允許池類檢測,並且如果對象被釋放兩次,立即除外。 '發佈兩次'的錯誤如果不能立即檢測到,可能會非常噁心 - 幾分鐘後會發生奇怪的行爲或崩潰,並且通常會在另一個模塊的另一個線程中發生。最好儘快檢測雙發佈!

我覺得用和可靠我池的水平轉儲到在1秒計時器狀態欄。如果發生泄漏,我可以看到它正在發生,並且通常可以瞭解當數字驚人地下降時,我正在進行的活動的泄漏位置。誰需要Valgrind的:)

在線程的主題,如果你必須讓你的池線程安全的,它可以幫助使用阻塞隊列。如果池耗盡,嘗試獲取對象的線程可能會一直等到它們被釋放,並且應用程序會減速而不是崩潰/死鎖。另外,請小心。虛假分享。您可能必須使用「填充」陣列數據成員來確保沒有兩個對象共享緩存行。