# thread_connection_pool **Repository Path**: chugehehe/thread-connection-pool ## Basic Information - **Project Name**: thread_connection_pool - **Description**: c++ 线程池 和 连接池 - **Primary Language**: C/C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-01-23 - **Last Updated**: 2025-07-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 线程池与连接池 ## 概述 在高性能应用程序中,资源管理和任务调度是至关重要的两个方面。为了优化资源利用率和提高程序执行效率,线程池和连接池被广泛应用于各种系统中。本项目实现了一个高效的线程池与连接池,旨在简化多线程任务管理和数据库连接的复用。 ### 线程池 线程池是一种预先创建一定数量线程并重复使用这些线程来执行多个任务的技术。通过管理线程的生命周期,线程池可以显著减少线程创建和销毁的开销,提高系统性能。 ### 连接池 连接池是一种管理数据库连接的技术,它预先创建一组数据库连接并将其储存在池中,供多个客户端共享使用。连接池可以有效减少频繁创建和销毁数据库连接的开销,提升数据库访问效率。 ## 工作原理 ### 线程池工作原理 1. **初始化**:在创建线程池时,预先生成固定数量的工作线程,这些线程在后台等待并处理任务。 2. **任务队列**:所有待处理的任务被存储在一个线程安全的任务队列中。 3. **任务调度**:当有新任务加入队列时,线程池中的空闲线程会取出任务并执行。 4. **线程复用**:执行完任务后,线程不会销毁,而是继续等待新的任务,提升资源利用率。 5. **停止线程池**:当不再需要时,可以通过调用 `stop()` 方法停止线程池,确保所有任务完成后释放线程资源。 ### 连接池工作原理 1. **初始化**:在创建连接池时,预先建立一定数量的数据库连接,并将其存储在空闲连接存储区。 2. **获取连接**:当需要数据库连接时,客户端从连接池中获取一个空闲连接。 3. **使用连接**:客户端使用获取的连接执行数据库操作,如查询、更新等。 4. **释放连接**:操作完成后,客户端将连接归还到连接池,供其他客户端复用。 5. **连接管理**:连接池会监控连接的状态,确保连接的有效性,并根据需要创建或销毁连接以适应系统负载。 ## 主要组件 ![image-20250123182547377](./README/image-20250123182547377.png) ### 线程池 (`ThreadPool`) - **构造函数**:`ThreadPool(size_t threadNum, size_t queueSize, ConnectionPool* connPool)` - `threadNum`:线程池中线程的数量。 - `queueSize`:任务队列的最大容量。 - `connPool`:数据库连接池的指针。 - **主要方法**: - `void start()`:启动线程池,创建并运行线程。 - `void stop()`:停止线程池,等待所有任务完成并释放资源。 - `void addTask(Task &&taskcb)`:向任务队列中添加新任务。 - `shared_ptr getConnection()`:从连接池中获取数据库连接。 - `void releaseConnection(shared_ptr &conn)`:将数据库连接归还连接池。 - **私有方法**: - `Task getTask()`:从任务队列中获取任务。 - `void doTask()`:线程执行的任务处理函数。 ### 任务队列 (`TaskQueue`) - **构造函数**:`TaskQueue(size_t size)` - `size`:任务队列的容量。 - **主要方法**: - `bool empty()`:检查任务队列是否为空。 - `bool full()`:检查任务队列是否已满。 - `void push(Task &&taskcb)`:向任务队列中添加任务。 - `Task pop()`:从任务队列中取出任务。 - `void wakeup()`:唤醒所有等待的线程。 ### 连接池 (`ConnectionPool`) - **构造函数**:`ConnectionPool(size_t maxConnSize, const string &host, const string &user, const string &password, const string &database)` - `maxConnSize`:连接池中最大连接数。 - `host`:数据库主机地址。 - `user`:数据库用户名。 - `password`:数据库密码。 - `database`:要连接的数据库名称。 - **主要方法**: - `shared_ptr getConnection()`:获取一个空闲的数据库连接。 - `void releaseConnection(shared_ptr &conn)`:释放数据库连接并归还连接池。 ### 数据库连接 (`MySQLConnection`) - **构造函数**:`MySQLConnection(const string &ip, const string &user, const string &password, const string &database)` - `ip`:数据库服务器IP地址。 - `user`:数据库用户名。 - `password`:数据库密码。 - `database`:要连接的数据库名称。 - **主要方法**: - `void query(const string &query)`:执行数据库查询操作。 - `void update(const string &query)`:执行数据库更新操作。 - `void transaction(const string &query)`:执行数据库事务操作。 ## 使用场景 ### 线程池使用场景 1. **高并发任务处理**:当系统需要处理大量并发任务时,线程池可以有效管理线程资源,避免频繁的线程创建和销毁带来的性能开销。 2. **服务器端应用**:在Web服务器、游戏服务器等需要处理多客户端请求的场景中,线程池可以用于高效地分配和管理请求处理线程。 3. **异步任务执行**:在需要异步执行后台任务的应用中,如日志记录、数据处理等,线程池可以提供方便的任务调度机制。 ### 连接池使用场景 1. **数据库连接复用**:在需要频繁访问数据库的应用中,连接池可以通过复用已有的数据库连接,提升数据库访问效率。 2. **资源受限环境**:在资源受限(如内存、数据库连接数限制)的环境中,连接池可以帮助控制数据库连接的数量,防止资源耗尽。 3. **多线程数据库操作**:在多线程应用中,通过连接池管理数据库连接,可以确保线程安全和连接资源的有效利用。 ## 使用说明 ### 初始化 1. **创建连接池**: ```cpp ConnectionPool dbPool(2, "127.0.0.1", "root", "1234", "test"); // 最大连接数为2 ``` 2. **创建线程池**: ```cpp ThreadPool pool(4, 100, &dbPool); // 4个线程,任务队列大小为100,使用dbPool进行数据库连接管理 pool.start(); // 启动线程池 ``` ### 添加任务 创建任务(继承自 `MyTask` 类)并添加到线程池: ```cpp // 创建数据库更新任务 vector> tasks; for (int i = 0; i < 5; ++i) { tasks.emplace_back(std::make_unique(pool, "INSERT INTO user (name, email) VALUES ('用户" + std::to_string(i) + "', 'user" + std::to_string(i) + "@example.com')")); } // 创建查询任务 tasks.emplace_back(std::make_unique(pool, "SELECT * FROM user")); // 将任务添加到线程池 for (auto& task : tasks) { pool.addTask([task = std::move(task)]() mutable { task->process(); }); } ``` ### 关闭线程池 在所有任务完成后,停止线程池: ```cpp pool.stop(); // 等待所有任务完成并停止线程池 ``` ## 示例代码 ### main.cpp ```cpp #include "MyTask.h" #include "ThreadPool.h" #include "MySQLConnection.h" #include #include #include #include #include using std::cout; using std::endl; using std::shared_ptr; using std::unique_ptr; using std::vector; using std::mutex; using std::condition_variable; using std::string; using std::cerr; // 定义一个数据库任务类 class DatabaseTask : public MyTask { public: DatabaseTask(ThreadPool& pool, const std::string& query) : pool(pool), query(query) {} void process() override { shared_ptr conn = nullptr; // 声明连接 try { conn = pool.getConnection(); // 从线程池的连接池获取连接 std::cout << "Executing update: " << query << std::endl; // 打印正在执行的更新 conn->update(query); // 执行更新 std::cout << "Update executed successfully." << std::endl; // 更新成功执行 } catch (const sql::SQLException &e) { std::cerr << "SQL Error: " << e.what() << std::endl; std::cerr << "Error Code: " << e.getErrorCode() << std::endl; std::cerr << "SQL State: " << e.getSQLState() << std::endl; } catch (const std::exception &e) { std::cerr << "Error: " << e.what() << std::endl; } // Ensure the connection is released if (conn) { pool.releaseConnection(conn); // Release the connection } } private: ThreadPool& pool; // 引用线程池 std::string query; // 查询字符串 }; // 定义一个查询任务类 class QueryTask : public MyTask { public: QueryTask(ThreadPool& pool, const std::string& query) : pool(pool), query(query) {} void process() override { shared_ptr conn; // 声明连接 try { conn = pool.getConnection(); // 从线程池的连接池获取连接 std::cout << "Executing query: " << query << std::endl; // 打印正在执行的查询 conn->query(query); // 执行查询并获取结果集 std::cout << "Query executed successfully." << std::endl; // 查询成功执行 } catch (const sql::SQLException &e) { std::cerr << "SQL Error: " << e.what() << std::endl; std::cerr << "Error Code: " << e.getErrorCode() << std::endl; std::cerr << "SQL State: " << e.getSQLState() << std::endl; } catch (const std::exception &e) { std::cerr << "Error: " << e.what() << std::endl; } // Ensure the connection is released if (conn) { pool.releaseConnection(conn); // Release the connection } } private: ThreadPool& pool; // 引用线程池 std::string query; // 查询字符串 }; void test() { // 记录程序开始时间 auto total_start = std::chrono::high_resolution_clock::now(); ConnectionPool dbPool(2, "127.0.0.1", "root", "1234", "test"); // 创建连接池 ThreadPool pool(4, 100, &dbPool); // 创建线程池,传递连接池引用 pool.start(); // 启动线程池 // 创建数据库更新任务 vector> tasks; for (int i = 0; i < 5; ++i) { tasks.emplace_back(std::make_unique(pool, "INSERT INTO user (name, email) VALUES ('用户" + std::to_string(i) + "', 'user" + std::to_string(i) + "@example.com')")); } // 创建查询任务 tasks.emplace_back(std::make_unique(pool, "SELECT * FROM user")); // 将任务添加到线程池 for (auto& task : tasks) { pool.addTask([task = std::move(task)]() mutable { task->process(); }); } // 等待所有任务完成并停止线程池 pool.stop(); // 记录程序结束时间 auto total_end = std::chrono::high_resolution_clock::now(); std::chrono::duration total_duration = total_end - total_start; cout << "总执行时间: " << total_duration.count() << " 秒" << endl; } int main() { test(); return 0; } ``` ## 参考资料 - [C++11 STL Documentation](https://en.cppreference.com/w/cpp/tuple/tie) - [Techie Delight - Print Binary Tree](https://www.techiedelight.com/c-program-print-binary-tree/) - [Gitee SSH 配置指南](https://gitee.com/help/articles/4136) ---