多线程环境下内存池的实现(C++)

1. 无锁情况下内存池存在的问题

可能发生一块内存被多个线程获取的情况,导致这几个线程的数据出现错乱。

#include <iostream>
#include <vector>
#include <thread>
#include <cstdlib>
#include <cstring>

const size_t BLOCK_SIZE = 64; // 每个块的大小
const size_t POOL_SIZE = 1024; // 内存池块数

class MemoryPool {
public:
    MemoryPool() {
        pool = malloc(BLOCK_SIZE * POOL_SIZE);
        memset(pool, 0, BLOCK_SIZE * POOL_SIZE);
        for (size_t i = 0; i < POOL_SIZE; ++i) {
            void* block = static_cast<char*>(pool) + i * BLOCK_SIZE;
            freeList.push_back(block); // 初始化空闲链表
        }
    }

    ~MemoryPool() {
        free(pool);
    }

    void* allocate() {
        if (freeList.empty()) {
            return nullptr; // 内存池已空
        }
        void* block = freeList.back();
        freeList.pop_back();
        return block;
    }

    void free(void* ptr) {
        freeList.push_back(ptr); // 将内存块放回空闲链表
    }

private:
    void* pool; // 内存池
    std::vector<void*> freeList; // 空闲链表
};

// 线程入口函数
void threadFunction(MemoryPool& memoryPool) {
    while (true)
    {
        void* ptr = memoryPool.allocate();
        if (ptr) {
            std::cout << "Thread " << std::this_thread::get_id() 
                    << " allocated memory at: " << ptr << std::endl;

            // 使用分配的内存
            std::memset(ptr, 0, BLOCK_SIZE); // 示例:清空分配的内存

            // 模拟业务处理时间
            std::this_thread::sleep_for(std::chrono::milliseconds(200));
            
            // 释放内存
            memoryPool.free(ptr);
            std::cout << "Thread " << std::this_thread::get_id() 
                    << " freed memory at: " << ptr << std::endl;
        } else {
            std::cout << "Thread " << std::this_thread::get_id() 
                    << " failed to allocate memory." << std::endl;
        }
    }
}

int main() {
    MemoryPool memoryPool;
    const int numThreads = 8;
    std::vector<std::thread> threads;
	
    for (int i = 0; i < numThreads; ++i) {
        threads.emplace_back(threadFunction, std::ref(memoryPool));
    }

    for (auto& thread : threads) {
        thread.join();
    }

    return 0;
}

在这里插入图片描述
内存块0x57ff7f529cf0被线程0x7f8eade00640获取后,还没释放,就被线程0x7f8eafc00640再次获取。

由于线程入口函数threadFunction与主函数main(),在下面的代码中不再发生变化,因此将省略这两个部分,聚焦于线程池类MemoryPool的实现。

2. 基于互斥锁mutex实现

class MemoryPool {
public:
    MemoryPool() {
        pool = malloc(BLOCK_SIZE * POOL_SIZE);
        memset(pool, 0, BLOCK_SIZE * POOL_SIZE);
        for (size_t i = 0; i < POOL_SIZE; ++i) {
            void* block = static_cast<char*>(pool) + i * BLOCK_SIZE;
            freeList.push_back(block); // 初始化空闲链表
        }
    }

    ~MemoryPool() {
        free(pool);
    }

    void* allocate() {
    	// 生命周期结束会自动释放锁,通过析构函数实现
        std::lock_guard<std::mutex> lock(mutex); 
        if (freeList.empty()) {
            return nullptr; // 内存池已空
        }
        void* block = freeList.back();
        freeList.pop_back();
        return block;
    }

    void free(void* ptr) {
    	// 生命周期结束会自动释放锁,通过析构函数实现
        std::lock_guard<std::mutex> lock(mutex);
        freeList.push_back(ptr); // 将内存块放回空闲链表
    }

private:
    void* pool; // 内存池
    std::vector<void*> freeList; // 空闲链表
    std::mutex mutex; // 互斥量
};

3. 基于原子变量atomic实现


class MemoryPool {
public:
    MemoryPool() {
        pool = malloc(BLOCK_SIZE * POOL_SIZE);
        memset(pool, 0, BLOCK_SIZE * POOL_SIZE);
        
        for (size_t i = 0; i < POOL_SIZE; ++i) {
            freeList[i].store(static_cast<char*>(pool) + i * BLOCK_SIZE);
        }
        freeHead.store(0);
    }

    ~MemoryPool() {
        free(pool);
    }

    void* allocate() {
        while (true){
            size_t head = freeHead.load();
            if (head >= POOL_SIZE) {
                return nullptr; // 内存池已空
            }

            // 尝试获取下一个空闲块
            void* block = freeList[head].load();
            if (freeHead.compare_exchange_strong(head, head + 1)) {
                // 成功获取
                return block;
            }
        }
    }

    void free(void* ptr) {
        while (true) {
            size_t head = freeHead.load();
            if (head == 0) {
                // 如果已满,直接返回
                return;
            }

            // 将块放回空闲链表
            freeList[head - 1].store(ptr);
            
            if (freeHead.compare_exchange_strong(head, head - 1)) {
                return; // 成功释放
            }
        }
    }

private:
    void* pool; // 内存池
    std::atomic<void*> freeList[POOL_SIZE]; // 空闲链表
    std::atomic<size_t> freeHead; // 当前空闲块的索引
};

4. 每个线程维护自己的内存池

class MemoryPool {
public:
    MemoryPool() {
        pool = malloc(BLOCK_SIZE * POOL_SIZE);
        memset(pool, 0, BLOCK_SIZE * POOL_SIZE);
        for (size_t i = 0; i < POOL_SIZE; ++i) {
            void* block = static_cast<char*>(pool) + i * BLOCK_SIZE;
            freeList.push_back(block); // 初始化空闲链表
        }
    }

    ~MemoryPool() {
        free(pool);
    }

    void* allocate() {
        if (freeList.empty()) {
            return nullptr; // 内存池已空
        }
        void* block = freeList.back();
        freeList.pop_back();
        return block;
    }

    void free(void* ptr) {
        freeList.push_back(ptr); // 将内存块放回空闲链表
    }

private:
    void* pool; // 内存池
    std::vector<void*> freeList; // 空闲链表
};


int main() {
    const int numThreads = 16;
    std::vector<std::thread> threads;
	std::vector<MemoryPool> pools;


    for (int i = 0; i < numThreads; ++i) {
        pools.push_back(MemoryPool()); // 为每个线程创建自己的内存池
        threads.emplace_back(threadFunction, std::ref(pools[i]));
    }

    for (auto& thread : threads) {
        thread.join();
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

it00zyq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值