Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 一种非阻塞线程安全的内存池实现_C++_Thread Safety_Nonblocking_Memory Pool - Fatal编程技术网

C++ 一种非阻塞线程安全的内存池实现

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

我需要一个简单的非阻塞静态块大小内存池。我在网上没有找到这样的网站。所以每个人都需要这样的解决方案。这个是免费的。。。仅适用于Win32

致以最良好的祝愿

弗里德里希

#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
    so
    r=A
    ,然后(在寄存器中)读取
    ecx=r->Next=B
  • 初始线程被抢占(或者,在另一个CPU上)一系列的
    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问题::)但我想你知道这一点。这看起来像是实现了我们所说的。不过,正如我在上一段中所描述的,您自己的版本离工作还不远。我也被这个问题蒙蔽了双眼: