线程池、内存池 和 数据库连接池

1. 线程池

概念

线程池是一种线程管理技术,在程序启动时预先创建固定数量的线程。这些线程存储在一个"池"中,可以重复使用,以处理任务请求,从而避免频繁创建和销毁线程带来的性能开销。

工作机制

  1. 初始化:在程序启动时,线程池创建一定数量的线程,并将它们处于等待(idle)状态。
  2. 任务提交:程序将任务提交到线程池的任务队列。
  3. 任务分配:线程池中的空闲线程会取出队列中的任务并执行。
  4. 线程复用:执行完任务后,线程返回线程池继续等待下一个任务。
  5. 线程终止 :程序关闭时,线程池会通知所有线程安全退出。

优点

  1. 提高性能:避免线程的频繁创建和销毁,提高系统效率。
  2. 控制并发:通过限制线程数量,避免线程过多导致资源耗尽。
  3. 任务管理:通过任务队列管理任务分配,便于扩展。
  4. 简单接口:使用线程池,开发者无需直接管理线程的生命周期。

实现细节

  • 线程同步:需要使用互斥锁和条件变量,确保线程安全。
  • 任务队列:保存提交的任务,线程从中取任务。
  • 线程状态管理 :需要管理线程的运行、等待和终止状态。

C++ 线程池详细实现

#include <iostream>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>

class ThreadPool {
public:
    ThreadPool(size_t numThreads) : stop(false) {
        // 创建线程池中的线程
        for (size_t i = 0; i < numThreads; ++i) {
            workers.emplace_back([this] {
                while (true) {
                    std::function<void()> task;
                    { // 获取任务(加锁)
                        std::unique_lock<std::mutex> lock(this->queueMutex);
                        this->condition.wait(lock, [this] {
                            return this->stop || !this->tasks.empty();
                        });

                        if (this->stop && this->tasks.empty()) return;

                        task = std::move(this->tasks.front());
                        this->tasks.pop();
                    }
                    task(); // 执行任务
                }
            });
        }
    }

    ~ThreadPool() {
        { // 通知所有线程退出
            std::unique_lock<std::mutex> lock(queueMutex);
            stop = true;
        }
        condition.notify_all(); // 唤醒所有线程
        for (std::thread &worker : workers) {
            worker.join(); // 等待线程退出
        }
    }

    template <class F>
    void enqueue(F&& task) {
        { // 加入任务队列
            std::unique_lock<std::mutex> lock(queueMutex);
            tasks.emplace(std::forward<F>(task));
        }
        condition.notify_one(); // 唤醒一个线程处理任务
    }

private:
    std::vector<std::thread> workers; // 工作线程
    std::queue<std::function<void()>> tasks; // 任务队列
    std::mutex queueMutex; // 队列互斥锁
    std::condition_variable condition; // 条件变量
    std::atomic<bool> stop; // 是否停止
};

// 使用示例
int main() {
    ThreadPool pool(4); // 创建包含 4 个线程的线程池

    for (int i = 0; i < 10; ++i) {
        pool.enqueue([i] {
            std::cout << "Task " << i << " is executed by thread " 
                      << std::this_thread::get_id() << std::endl;
        });
    }

    std::this_thread::sleep_for(std::chrono::seconds(1)); // 等待任务完成
    return 0;
}

2. 内存池

概念

内存池是一种优化内存分配的技术,通过预分配一块大内存,将其划分为多个小块,并用来满足内存分配需求。使用完成后,小块可以快速回收,避免频繁调用系统的 mallocfree

工作机制

  1. 预分配:程序启动时,分配一块连续的内存区域。
  2. 分配小块:将内存池划分为大小相等的块,每次分配时直接返回一块。
  3. 回收小块:使用完成后,将内存块归还到池中,以供再次使用。

优点

  1. 性能提升:避免多次调用系统的内存分配接口,降低开销。
  2. 内存碎片减少:分配小块内存,防止内存碎片问题。
  3. 缓存性能提升:使用连续的内存区域,提升缓存命中率。

实现细节

  • 链表管理:使用链表存储空闲块。
  • 内存对齐:确保内存地址对齐,提高访问效率。
  • 线程安全:在多线程场景中需要加锁保护。

C++ 内存池详细实现

cpp 复制代码
#include <iostream>
#include <vector>

class MemoryPool {
public:
    MemoryPool(size_t blockSize, size_t blockCount)
        : blockSize(blockSize), blockCount(blockCount) {
        pool = std::malloc(blockSize * blockCount); // 预分配大块内存
        for (size_t i = 0; i < blockCount; ++i) {
            freeBlocks.push_back(static_cast<char*>(pool) + i * blockSize); // 将内存块加入空闲列表
        }
    }

    ~MemoryPool() {
        std::free(pool); // 释放预分配的内存
    }

    void* allocate() {
        if (freeBlocks.empty()) {
            throw std::bad_alloc(); // 如果没有空闲块,抛出异常
        }
        void* block = freeBlocks.back();
        freeBlocks.pop_back();
        return block; // 返回空闲块
    }

    void deallocate(void* block) {
        freeBlocks.push_back(static_cast<char*>(block)); // 回收内存块
    }

private:
    void* pool; // 预分配的内存
    size_t blockSize; // 每块大小
    size_t blockCount; // 块的总数
    std::vector<void*> freeBlocks; // 空闲块列表
};

// 使用示例
int main() {
    MemoryPool pool(128, 10); // 每块 128 字节,共 10 块

    void* block1 = pool.allocate(); // 分配内存块
    void* block2 = pool.allocate();

    std::cout << "Allocated blocks at: " << block1 << " and " << block2 << std::endl;

    pool.deallocate(block1); // 回收内存块
    pool.deallocate(block2);

    return 0;
}

3. 数据库连接池

概念

数据库连接池是一种数据库连接管理技术,用于在程序启动时预先创建多个连接,并根据需要分配给线程使用。连接用完后归还到池中。

工作机制

  1. 初始化:创建一定数量的数据库连接。
  2. 分配连接:请求数据库时,从池中分配连接。
  3. 归还连接:使用完成后,将连接归还池中。
  4. 销毁连接:程序关闭时,销毁所有连接。

优点

  1. 提高效率:避免频繁建立和销毁连接。
  2. 资源复用:复用连接,减少资源占用。
  3. 高并发支持:支持高并发访问数据库。

C++ 数据库连接池详细实现

下面是一个连接池示例,基于 MySQL C++ API:

cpp 复制代码
#include <iostream>
#include <queue>
#include <mutex>
#include <memory>
#include <mysql/mysql.h>

class DBConnection {
public:
    DBConnection() {
        conn = mysql_init(nullptr);
        if (!mysql_real_connect(conn, "localhost", "user", "password", "database", 3306, nullptr, 0)) {
            throw std::runtime_error("Database connection failed");
        }
    }

    ~DBConnection() {
        if (conn) mysql_close(conn);
    }

    MYSQL* get() {
        return conn;
    }

private:
    MYSQL* conn;
};

class ConnectionPool {
public:
    ConnectionPool(size_t poolSize) {
        for (size_t i = 0; i < poolSize; ++i) {
            connections.push(std::make_shared<DBConnection>());
        }
    }

    std::shared_ptr<DBConnection> acquire() {
        std::unique_lock<std::mutex> lock(mutex);
        while (connections.empty()) {
            condition.wait(lock);
        }
        auto conn = connections.front();
        connections.pop();
        return conn;
    }

    void release(std::shared_ptr<DBConnection> conn) {
        std::unique_lock<std::mutex> lock(mutex);
        connections.push(conn);
        condition.notify_one();
    }

private:
    std::queue<std::shared_ptr<DBConnection>> connections;
    std::mutex mutex;
    std::condition_variable condition;
};

// 使用示例
int main() {
    ConnectionPool pool(4); // 创建连接池

    auto connection = pool.acquire(); // 获取连接
    MYSQL* conn = connection->get();

    if (mysql_query(conn, "SELECT VERSION()")) {
        std::cerr << "Query failed: " << mysql_error(conn) << std::endl;
    } else {
        MYSQL_RES* res = mysql_store_result(conn);
        MYSQL_ROW row = mysql_fetch_row(res);
        std::cout << "MySQL version: " << row[0] << std::endl;
        mysql_free_result(res);
    }

    pool.release(connection); // 释放连接
    return 0;
}

总结

线程池

  • 用途:任务调度,高并发任务管理。
  • 优点:复用线程,提高资源利用率。

内存池

  • 用途:高频内存分配和回收场景。
  • 优点:减少系统调用,提升性能。

数据库连接池

  • 用途:高并发数据库访问场景。
  • 优点:减少连接开销,提高访问效率。
相关推荐
CS软件开发框架3 分钟前
发布/部署WebApi服务器(IIS+.NET8+ASP.NETCore)
服务器·c#·asp.net·.net·.netcore
人工智能有点9 分钟前
Linux中的service命令
linux·服务器·ubuntu·docker
AiFlutter15 分钟前
Linux安全之SSH密钥创建及密钥登陆
linux·安全·ssh
一种天气22 分钟前
SQLServer利用QQ邮箱做SMTP服务器发邮件
服务器·数据库·sqlserver
天空之外13640 分钟前
docker离线安装、linux 安装docker
linux·docker·容器
我言秋日胜春朝★1 小时前
【Linux】基础IO-----重定向与缓冲区
linux·运维·服务器
shelby_loo1 小时前
在 Ubuntu 下通过 Docker 部署 Cloudflared Tunnel 服务器
服务器·ubuntu·docker
请你喝好果汁6411 小时前
GTF转为excel文件
java·linux·excel
棉花糖网络安全圈1 小时前
Fortify 24.2.0版本最新版 win/mac/linux
linux·运维·macos·网络安全