C++ 一种非阻塞线程安全的内存池实现
我需要一个简单的非阻塞静态块大小内存池。我在网上没有找到这样的网站。所以每个人都需要这样的解决方案。这个是免费的。。。仅适用于Win32 致以最良好的祝愿 弗里德里希C++ 一种非阻塞线程安全的内存池实现,c++,thread-safety,nonblocking,memory-pool,C++,Thread Safety,Nonblocking,Memory Pool,我需要一个简单的非阻塞静态块大小内存池。我在网上没有找到这样的网站。所以每个人都需要这样的解决方案。这个是免费的。。。仅适用于Win32 致以最良好的祝愿 弗里德里希 #ifndef MEMPOOL_HPP_INCLUDED #define MEMPOOL_HPP_INCLUDED #include "atomic.hpp" #include "static_assert.hpp" #pragma warning( push ) #pragma warning( disable : 4311
#ifndef MEMPOOL_HPP_INCLUDED
#define MEMPOOL_HPP_INCLUDED
#include "atomic.hpp"
#include "static_assert.hpp"
#pragma warning( push )
#pragma warning( disable : 4311 ) // warning C4311: 'Typumwandlung'
/// @brief Block-free memory-pool implemenation
/// @tparam T Object-type to be saved within the memory-pool.
/// @tparam S Capacy of the memory-pool.
template <typename T, int S>
class MemoryPool
{
private:
STATIC_ASSERT(sizeof(int) == sizeof(void*), "Well, ...");
public:
/// @brief Object-type saved within the pool.
typedef T TYPE;
enum
{
/// @brief Capacy of the memory-pool.
SIZE = S
};
private:
/// @brief Chunks, that holds the memory
struct Chunk
{
/// @brief Single-linked list.
Chunk* Next;
/// @brief The value
/// We do not call the default constructor this way.
char Value[sizeof(TYPE)];
};
/// @brief The root object.
Chunk* Root;
/// @brief The pool
Chunk Pool[SIZE];
private:
// do not allow copying
MemoryPool(const MemoryPool&);
MemoryPool& operator=(const MemoryPool&);
void free(Chunk* c)
{
c->Next = Root;
while(!CompareAndSwap((int*)&Root, (int)c->Next, (int)c))
{
c->Next = Root;
}
}
public:
/// Default constructor
/// Creates an empty memory-pool.
/// Invalidates all the memory.
MemoryPool()
: Root(0)
{
for(int i = 0; i < SIZE; i++)
{
MemoryPool::free(&Pool[i]);
}
}
/// @brief Frees a chunk of memory, that was allocated by MemoryPool::malloc
/// @param _Chunk A chunk of memory, that was allocated by MemoryPool::malloc
/// This function will not call the destructor.
/// Thread-safe, non-blocking
void free(T* _Chunk)
{
if(!_Chunk)
return;
Chunk* c = (Chunk*)((int)(_Chunk) - sizeof(Chunk*));
if(c < &Pool[0] || c > &Pool[SIZE - 1])
return;
MemoryPool::free(c);
}
/// @brief Returns a pointer to a chunk of memory
/// @return 0 on a memory shortage
/// @return A pointer to a chunk of memory
/// This function will not call the constructor.
/// Thread-safe, non-blocking
T* malloc()
{
Chunk* r = Root;
if(!r)
return 0;
while(!CompareAndSwap((int*)&Root, (int)r, (int)r->Next))
{
r = Root;
if(!r)
return 0;
}
return &(r->Value);
}
};
#pragma warning( pop )
#endif // MEMPOOL_HPP_INCLUDED
/// @brief Lock-free memory-pool implementation
/// @tparam T Type stored within the memory-pool
/// @tparam S Number of elements stored in the memory-pool.
template <typename T, int S>
class MemoryPool
{
public:
/// @brief Type stored within the memory-pool.
typedef T TYPE;
enum
{
/// @brief Number of enrties in the memory-pool.
SIZE = S
};
private:
// we need to align the memory-pool-chunks.
#pragma pack(push, MEMORY_ALLOCATION_ALIGNMENT)
/// @brief The memory-chunk used by the memory-pool.
template <typename TYPE>
struct MemoryChunk
{
/// @brief Next entry in the single-linked list.
SLIST_ENTRY Next;
/// @brief The value stored within the memory-pool.
/// Do not call the constructor
char Value[sizeof(TYPE)];
};
typedef MemoryChunk<TYPE> CHUNK_TYPE;
#pragma pack(pop, MEMORY_ALLOCATION_ALIGNMENT)
/// @brief Head of the single-linked list.
SLIST_HEADER Head;
/// @brief The pool itself
CHUNK_TYPE Pool[SIZE];
// no copying is supported
MemoryPool& operator=(const MemoryPool&);
MemoryPool(const MemoryPool&);
public:
/// @brief Constructs the memory-pool.
MemoryPool()
{
InitializeSListHead(&Head);
for(int i = 0; i < SIZE; i++)
{
InterlockedPushEntrySList(&Head, &Pool[i].Next);
}
}
/// @brief Free the memory-pool.
~MemoryPool()
{
InterlockedFlushSList(&Head);
}
/// @brief Allocates a memory chunk
/// @return 0 if none is free
/// @return Pointer to a free memory chunk (the constructor is not called!)
TYPE* Allocate()
{
CHUNK_TYPE* c = reinterpret_cast<CHUNK_TYPE*>(InterlockedPopEntrySList(&Head));
if(c)
return reinterpret_cast<TYPE*>(&c->Value[0]);
else
return 0;
}
/// @brief Deallocates a memory chunk (the destructor is not called)
/// @param c Point to the memory-chunk allocated by us.
void Deallocate(void* c)
{
if(c < static_cast<void*>(&Pool[0]) || c > static_cast<void*>(&Pool[SIZE]))
return; // was not allocated by us
char* p = static_cast<char*>(c);
p -= sizeof(SLIST_ENTRY);
CHUNK_TYPE* t = reinterpret_cast<CHUNK_TYPE*>(p);
InterlockedPushEntrySList(&Head, &t->Next);
}
};
这种方法的问题在于
malloc
中存在竞争条件:
while(!CompareAndSwap((int*)&Root, (int)r, (int)r->Next))
考虑以下操作顺序:
Root=A,A->next=B,…
r=Root
sor=A
,然后(在寄存器中)读取ecx=r->Next=B
malloc
和free
发生,使得a
被使用一段时间,最后被释放Root=A,A->next=ZZZ,…
cmpxchg
并成功,因为Root==r==A
,因此设置Root=ecx=B
如果您有一个双字
cmpxchg
,例如cmpxchg8b
,则可以解决此问题。您只需在列表标题旁边包含一个序列号,这样,如果您被如上(3)所述的中断,那么如果比较失败。只要每个malloc
都交换指针并增加序列号,free
端可以使用窄版本。谢谢您的评论。这一个可以与WinXP和更新版本一起使用。前面提到的实现仍然可以与PowerPC体系结构一起使用(如果您有正确的CompareAndSwap实现,请参阅“http://publib.boulder.ibm.com/infocenter/aix/v6r1/topic/com.ibm.aix.aixassem/doc/alangref/stwcx.htm"
致以最良好的祝愿
弗里德里希
#ifndef MEMPOOL_HPP_INCLUDED
#define MEMPOOL_HPP_INCLUDED
#include "atomic.hpp"
#include "static_assert.hpp"
#pragma warning( push )
#pragma warning( disable : 4311 ) // warning C4311: 'Typumwandlung'
/// @brief Block-free memory-pool implemenation
/// @tparam T Object-type to be saved within the memory-pool.
/// @tparam S Capacy of the memory-pool.
template <typename T, int S>
class MemoryPool
{
private:
STATIC_ASSERT(sizeof(int) == sizeof(void*), "Well, ...");
public:
/// @brief Object-type saved within the pool.
typedef T TYPE;
enum
{
/// @brief Capacy of the memory-pool.
SIZE = S
};
private:
/// @brief Chunks, that holds the memory
struct Chunk
{
/// @brief Single-linked list.
Chunk* Next;
/// @brief The value
/// We do not call the default constructor this way.
char Value[sizeof(TYPE)];
};
/// @brief The root object.
Chunk* Root;
/// @brief The pool
Chunk Pool[SIZE];
private:
// do not allow copying
MemoryPool(const MemoryPool&);
MemoryPool& operator=(const MemoryPool&);
void free(Chunk* c)
{
c->Next = Root;
while(!CompareAndSwap((int*)&Root, (int)c->Next, (int)c))
{
c->Next = Root;
}
}
public:
/// Default constructor
/// Creates an empty memory-pool.
/// Invalidates all the memory.
MemoryPool()
: Root(0)
{
for(int i = 0; i < SIZE; i++)
{
MemoryPool::free(&Pool[i]);
}
}
/// @brief Frees a chunk of memory, that was allocated by MemoryPool::malloc
/// @param _Chunk A chunk of memory, that was allocated by MemoryPool::malloc
/// This function will not call the destructor.
/// Thread-safe, non-blocking
void free(T* _Chunk)
{
if(!_Chunk)
return;
Chunk* c = (Chunk*)((int)(_Chunk) - sizeof(Chunk*));
if(c < &Pool[0] || c > &Pool[SIZE - 1])
return;
MemoryPool::free(c);
}
/// @brief Returns a pointer to a chunk of memory
/// @return 0 on a memory shortage
/// @return A pointer to a chunk of memory
/// This function will not call the constructor.
/// Thread-safe, non-blocking
T* malloc()
{
Chunk* r = Root;
if(!r)
return 0;
while(!CompareAndSwap((int*)&Root, (int)r, (int)r->Next))
{
r = Root;
if(!r)
return 0;
}
return &(r->Value);
}
};
#pragma warning( pop )
#endif // MEMPOOL_HPP_INCLUDED
/// @brief Lock-free memory-pool implementation
/// @tparam T Type stored within the memory-pool
/// @tparam S Number of elements stored in the memory-pool.
template <typename T, int S>
class MemoryPool
{
public:
/// @brief Type stored within the memory-pool.
typedef T TYPE;
enum
{
/// @brief Number of enrties in the memory-pool.
SIZE = S
};
private:
// we need to align the memory-pool-chunks.
#pragma pack(push, MEMORY_ALLOCATION_ALIGNMENT)
/// @brief The memory-chunk used by the memory-pool.
template <typename TYPE>
struct MemoryChunk
{
/// @brief Next entry in the single-linked list.
SLIST_ENTRY Next;
/// @brief The value stored within the memory-pool.
/// Do not call the constructor
char Value[sizeof(TYPE)];
};
typedef MemoryChunk<TYPE> CHUNK_TYPE;
#pragma pack(pop, MEMORY_ALLOCATION_ALIGNMENT)
/// @brief Head of the single-linked list.
SLIST_HEADER Head;
/// @brief The pool itself
CHUNK_TYPE Pool[SIZE];
// no copying is supported
MemoryPool& operator=(const MemoryPool&);
MemoryPool(const MemoryPool&);
public:
/// @brief Constructs the memory-pool.
MemoryPool()
{
InitializeSListHead(&Head);
for(int i = 0; i < SIZE; i++)
{
InterlockedPushEntrySList(&Head, &Pool[i].Next);
}
}
/// @brief Free the memory-pool.
~MemoryPool()
{
InterlockedFlushSList(&Head);
}
/// @brief Allocates a memory chunk
/// @return 0 if none is free
/// @return Pointer to a free memory chunk (the constructor is not called!)
TYPE* Allocate()
{
CHUNK_TYPE* c = reinterpret_cast<CHUNK_TYPE*>(InterlockedPopEntrySList(&Head));
if(c)
return reinterpret_cast<TYPE*>(&c->Value[0]);
else
return 0;
}
/// @brief Deallocates a memory chunk (the destructor is not called)
/// @param c Point to the memory-chunk allocated by us.
void Deallocate(void* c)
{
if(c < static_cast<void*>(&Pool[0]) || c > static_cast<void*>(&Pool[SIZE]))
return; // was not allocated by us
char* p = static_cast<char*>(c);
p -= sizeof(SLIST_ENTRY);
CHUNK_TYPE* t = reinterpret_cast<CHUNK_TYPE*>(p);
InterlockedPushEntrySList(&Head, &t->Next);
}
};
//@简短的无锁内存池实现
///@tparam T类型存储在内存池中
///@tparam存储在内存池中的元素数。
模板
类内存池
{
公众:
///@存储在内存池中的简短类型。
T型;
枚举
{
///@内存池中的ENRTIE的简短数目。
尺寸=S
};
私人:
//我们需要对齐内存池块。
#pragma包(推送、内存分配和对齐)
///@brief内存池使用的内存块。
模板
结构内存块
{
///@brief单链表中的下一个条目。
下一步滑入;
///@brief内存池中存储的值。
///不要调用构造函数
字符值[sizeof(类型)];
};
typedef MemoryChunk CHUNK_TYPE;
#pragma包(pop、内存分配和对齐)
///@单链表的简短标题。
滑动头;
///@简要介绍一下游泳池本身
区块类型池[大小];
//不支持复制
MemoryPool&运算符=(常量MemoryPool&);
MemoryPool(const MemoryPool&);
公众:
///@brief构造内存池。
MemoryPool()
{
初始化ListHead(&Head);
对于(int i=0;iValue[0]);
其他的
返回0;
}
///@brief解除分配内存块(未调用析构函数)
///@param c指向我们分配的内存块。
无效解除分配(无效*c)
{
if(cstatic_cast(&Pool[SIZE]))
return;//未由我们分配
char*p=静态_cast(c);
p-=sizeof(SLIST_条目);
CHUNK_TYPE*t=重新解释铸件(p);
联锁PushEntrySlist(&Head,&t->Next);
}
};
谢谢,但这类帖子就不是了。顺便说一句:如果这只适用于Windows:为什么不使用InterlocatedXYZ()?7个问题,0个答案,0个投票,0个接受。谢谢,但这类用户也不例外。我继续回答,因为尽管原始海报没有意识到这一点,他需要帮助。你应该保持网站的问答格式,将帖子的答案部分向下移动到一个答案。又名ABA问题::)但我想你知道这一点。这看起来像是实现了我们所说的。不过,正如我在上一段中所描述的,您自己的版本离工作还不远。我也被这个问题蒙蔽了双眼: