1. 线程池
概念
线程池是一种线程管理技术,在程序启动时预先创建固定数量的线程。这些线程存储在一个"池"中,可以重复使用,以处理任务请求,从而避免频繁创建和销毁线程带来的性能开销。
工作机制
- 初始化:在程序启动时,线程池创建一定数量的线程,并将它们处于等待(idle)状态。
- 任务提交:程序将任务提交到线程池的任务队列。
- 任务分配:线程池中的空闲线程会取出队列中的任务并执行。
- 线程复用:执行完任务后,线程返回线程池继续等待下一个任务。
- 线程终止 :程序关闭时,线程池会通知所有线程安全退出。
优点
- 提高性能:避免线程的频繁创建和销毁,提高系统效率。
- 控制并发:通过限制线程数量,避免线程过多导致资源耗尽。
- 任务管理:通过任务队列管理任务分配,便于扩展。
- 简单接口:使用线程池,开发者无需直接管理线程的生命周期。
实现细节
- 线程同步:需要使用互斥锁和条件变量,确保线程安全。
- 任务队列:保存提交的任务,线程从中取任务。
- 线程状态管理 :需要管理线程的运行、等待和终止状态。
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. 内存池
概念
内存池是一种优化内存分配的技术,通过预分配一块大内存,将其划分为多个小块,并用来满足内存分配需求。使用完成后,小块可以快速回收,避免频繁调用系统的 malloc
和 free
。
工作机制
- 预分配:程序启动时,分配一块连续的内存区域。
- 分配小块:将内存池划分为大小相等的块,每次分配时直接返回一块。
- 回收小块:使用完成后,将内存块归还到池中,以供再次使用。
优点
- 性能提升:避免多次调用系统的内存分配接口,降低开销。
- 内存碎片减少:分配小块内存,防止内存碎片问题。
- 缓存性能提升:使用连续的内存区域,提升缓存命中率。
实现细节
- 链表管理:使用链表存储空闲块。
- 内存对齐:确保内存地址对齐,提高访问效率。
- 线程安全:在多线程场景中需要加锁保护。
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. 数据库连接池
概念
数据库连接池是一种数据库连接管理技术,用于在程序启动时预先创建多个连接,并根据需要分配给线程使用。连接用完后归还到池中。
工作机制
- 初始化:创建一定数量的数据库连接。
- 分配连接:请求数据库时,从池中分配连接。
- 归还连接:使用完成后,将连接归还池中。
- 销毁连接:程序关闭时,销毁所有连接。
优点
- 提高效率:避免频繁建立和销毁连接。
- 资源复用:复用连接,减少资源占用。
- 高并发支持:支持高并发访问数据库。
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;
}
总结
线程池
- 用途:任务调度,高并发任务管理。
- 优点:复用线程,提高资源利用率。
内存池
- 用途:高频内存分配和回收场景。
- 优点:减少系统调用,提升性能。
数据库连接池
- 用途:高并发数据库访问场景。
- 优点:减少连接开销,提高访问效率。