在重新考虑设计并从稻田中获得一些输入之后,我想出了类似的东西,但我想知道它的正确性,当我运行它时似乎很好......这个想法是预分配的对象继承自以下内容:
struct Node
{
void* pool;
};
这样,我们在每个分配的对象中注入一个指向它的池的指针,以便稍后释放它。然后我们有:
template<class T, int thesize>
struct MemPool
{
T* getNext();
void free(T* ptr);
struct ThreadLocalMemPool
{
T* getNextTL();
void freeTL();
int size;
vector<T*> buffer;
vector<int> freeList;
int freeListIdx;
int bufferIdx;
ThreadLocalMemPool* nextTlPool; //within a thread's context a linked list
};
int size;
threadlocal ThreadLocalMemPool* tlPool; //one of these per thread
};
所以基本上我说它MemPool<Cat, 100>
给了我一个内存池,对于它的每个线程,getNexts
它都会实例化一个线程本地内存池。尺寸我在内部四舍五入到最接近的 2 次方,以便轻松取模(为简单起见,我将其省略)。因为getNext()
对于每个线程都是本地的,所以它不需要锁定,我尝试使用原子作为释放部分,如下所示:
T* ThreadLocalMemPool::getNextTL()
{
int iHead = ++bufferIdx % size;
int iTail = freeListIdx % size;
if (iHead != iTail) // If head reaches tail, the free list is empty.
{
int & idx = freeList[iHead];
while (idx == DIRTY) {}
return buffer[idx];
}
else
{
bufferIdx--; //we will recheck next time
if (nextTLPool)
return nextTLPool->getNextTL();
else
//set nextTLPool to a new ThreadLocalMemPool and return getNextTL() from it..
}
}
void ThreadLocalMemPool::free(T* ptr)
{
//the outer struct handles calling this in the right ThreadLocalMemPool
//we compute the index in the pool from which this pool came from by subtracting from
//its address the address of the first pointer in this guys buffer
int idx = computeAsInComment(ptr);
int oldListIdx = atomic_increment_returns_old_value(freeListIdx);
freeList[oldListIdx % size] = idx;
}
现在,这个想法是freeListIdx
总是落后bufferIdx
于池中,因为你不能(我假设正确使用)释放超过你分配的更多。对 free 的调用会同步它们将缓冲区索引返回到空闲列表的顺序,并且 getNext 将在循环返回时接收到这一点。我一直在考虑它,并没有看到逻辑上有任何语义上的错误,它看起来是正确的还是有一些微妙的东西可以破坏它?