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

文章目录

  • [1. 无锁情况下内存池存在的问题](#1. 无锁情况下内存池存在的问题)
  • [2. 基于互斥锁mutex实现](#2. 基于互斥锁mutex实现)
  • [3. 基于原子变量atomic实现](#3. 基于原子变量atomic实现)
  • [4. 每个线程维护自己的内存池](#4. 每个线程维护自己的内存池)

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

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

cpp 复制代码
#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实现

cpp 复制代码
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实现

cpp 复制代码
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. 每个线程维护自己的内存池

cpp 复制代码
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;
}
相关推荐
f***01937 分钟前
CC++链接数据库(MySQL)超级详细指南
c语言·数据库·c++
合方圆~小文16 分钟前
球型摄像机作为现代监控系统的核心设备
java·数据库·c++·人工智能
椰萝Yerosius1 小时前
[题解]2024CCPC郑州站——Z-order Curve
c++·算法
滨HI04 小时前
C++ opencv简化轮廓
开发语言·c++·opencv
学习路上_write4 小时前
FREERTOS_互斥量_创建和使用
c语言·开发语言·c++·stm32·单片机·嵌入式硬件
闻缺陷则喜何志丹6 小时前
【SOSDP模板 容斥原理 逆向思考】3757. 有效子序列的数量|分数未知
c++·算法·力扣·容斥原理·sosdp·逆向思考
BestOrNothing_20156 小时前
一篇搞懂 C++ 重载:函数重载 + 运算符重载,从入门到会用(含 ++、<<、== 实战)
c++·函数重载·运算符重载·operator·前置后置++·重载与重写
2501_941144426 小时前
Python + C++ 异构微服务设计与优化
c++·python·微服务
程序猿编码6 小时前
PRINCE算法的密码生成器:原理与设计思路(C/C++代码实现)
c语言·网络·c++·算法·安全·prince
charlie1145141917 小时前
深入理解C/C++的编译链接技术6——A2:动态库设计基础之ABI设计接口
c语言·开发语言·c++·学习·动态库·函数