多线程环境下内存池的实现(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;
}
相关推荐
Death20036 分钟前
PCL库中的算法封装详解
c++·qt·算法·3d
勇敢滴勇37 分钟前
【C++】继承和多态常见的面试问题
java·c++·面试
Qhumaing1 小时前
小白C/C++语言常见问题(持续更新)
c语言·c++·算法
小柯J桑_1 小时前
C++:二叉搜索树(迭代)
c++·二叉搜索树
铭正1 小时前
c++时间形式转换
c++·时间格式转换
啦啦啦!1 小时前
2024年10月30日(双指针算法)
c++·算法·leetcode
△曉風殘月〆2 小时前
C#与C++结构体的交互
c++·c#·p/invoke
hugerat2 小时前
嵌入式linux跨平台基于mongoose的TCP C++类的源码
linux·c++·tcp/ip
无敌岩雀2 小时前
C++设计模式创建型模式———单例模式
c++·单例模式·设计模式
canyuemanyue2 小时前
C++单例模式
开发语言·c++·单例模式