多线程环境下内存池的实现(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;
}
相关推荐
唐诺1 小时前
几种广泛使用的 C++ 编译器
c++·编译器
冷眼看人间恩怨2 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
红龙创客2 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin2 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
yuanbenshidiaos4 小时前
c++---------数据类型
java·jvm·c++
十年一梦实验室4 小时前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵
taoyong0014 小时前
代码随想录算法训练营第十一天-239.滑动窗口最大值
c++·算法
这是我584 小时前
C++打小怪游戏
c++·其他·游戏·visual studio·小怪·大型·怪物
fpcc4 小时前
跟我学c++中级篇——C++中的缓存利用
c++·缓存
呆萌很5 小时前
C++ 集合 list 使用
c++