长时数据库访问任务执行中遇通信故障的中断方案推荐
最优实现方案推荐
针对你的需求,下面是几种实用的实现方案,按优先级排序:
方案1:原子变量+统一异常抛出(兼容性强,改动量小)
首先把postgres_not_ok改成**std::atomic<bool>**——普通bool可能因为编译器优化,导致任务线程看不到监控线程更新的最新状态,原子变量能保证多线程间的状态可见性。
然后封装一个统一的连接检查函数,在每个数据库操作的开头(或耗时操作的中间节点)调用,一旦检测到连接中断就抛出自定义异常,最后在任务函数里统一捕获异常并退出,不用在每个函数里写重复的判断逻辑。
代码示例:
#include <atomic> #include <stdexcept> // 用原子变量存储连接状态,确保线程安全可见 std::atomic<bool> postgres_not_ok{false}; // 自定义异常,标识连接中断 class DbConnectionLostException : public std::runtime_error { public: using std::runtime_error::runtime_error; }; // 统一的连接检查工具函数 void checkDbConnection() { if (postgres_not_ok.load(std::memory_order_acquire)) { throw DbConnectionLostException("数据库连接已中断"); } } // 修改后的数据库操作函数 void EnergyCalculator::getSolarDataFromPostgre() { checkDbConnection(); // 原有业务逻辑... // 如果中间有长时间运行的步骤,也可以插入checkDbConnection(); } void EnergyCalculator::calculatePowerAndSaveInPostgres() { checkDbConnection(); // 原有业务逻辑... } // 主任务函数 void EnergyCalculator::dataProcessingTask() { try { checkDbConnection(); getSolarDataFromPostgre(); getPowerDataFromPostgre(); getEnergyDataFromPostgre(); ... calculatePowerAndSaveInPostgres(); calculateEnergyAndSaveInPostgres(); calculateExpensesAndSaveInPostgres(); ... } catch (const DbConnectionLostException&) { // 可选:记录中断日志 return; } }
优势:
- 不需要大幅修改原有代码,只给数据库操作加统一的检查入口
- 原子变量避免了多线程状态同步问题
- 异常机制让任务能立即终止,不用在每个分支写return
方案2:利用数据库驱动的异常机制(最省心)
如果你用的PostgreSQL客户端驱动(比如libpqxx)支持异常配置,可以让驱动在连接中断时自动抛出异常,这样连手动检查postgres_not_ok都省了——一旦数据库操作失败(比如连接断了),驱动直接抛异常,任务函数里统一捕获处理即可。
代码示例:
// 以libpqxx为例,初始化连接时开启全异常模式 pqxx::connection db_conn("dbname=your_db user=your_user"); db_conn.exceptions(pqxx::except_all); // 让所有数据库错误都抛出异常 void EnergyCalculator::dataProcessingTask() { try { getSolarDataFromPostgre(); // 内部用驱动操作,连接断了自动抛异常 getPowerDataFromPostgre(); ... calculatePowerAndSaveInPostgres(); ... } catch (const pqxx::sql_error& e) { // 判断是否是连接中断类错误 if (std::string(e.what()).find("connection lost") != std::string::npos) { postgres_not_ok.store(true, std::memory_order_release); // 同步给监控线程 return; } // 其他数据库错误可以按需处理,或者重新抛出 throw; } }
优势:
- 完全不用手动维护连接状态检查,由驱动自动感知连接问题
- 能捕获所有突发的连接异常(比如网络断连)
方案3:C++20线程停止机制(备选)
如果你的项目用C++20及以上,可以用std::stop_token实现线程停止请求。监控线程检测到连接中断时,发送停止请求,任务线程在关键节点检查是否需要停止。但要注意:如果任务中有阻塞的数据库调用,得确保这些调用能响应停止请求,不然没法立即中断。
代码示例:
#include <stop_token> #include <thread> std::stop_source stop_src; std::atomic<bool> postgres_not_ok{false}; // 监控线程逻辑 void monitorDbConnection() { while (true) { if (checkDbConnectionFailed()) { // 你的连接检查逻辑 postgres_not_ok.store(true); stop_src.request_stop(); // 发送停止请求 break; } std::this_thread::sleep_for(std::chrono::seconds(1)); } } // 任务线程接收stop_token void EnergyCalculator::dataProcessingTask(std::stop_token st) { if (postgres_not_ok) return; getSolarDataFromPostgre(); if (st.stop_requested()) return; getPowerDataFromPostgre(); if (st.stop_requested()) return; // 后续操作同理,在关键节点检查停止请求 }
注意:
- 需要手动在任务的关键步骤检查停止请求,本质和方案1类似,但用标准库机制更规范
- 阻塞操作如果不支持响应停止,会导致无法立即中断任务
优先级建议
- 优先选方案2:驱动支持的话最省心,自动处理所有连接异常
- 其次选方案1:兼容性好,不依赖驱动特性,代码改动小
- 方案3作为备选:适合C++20+环境,需要严格控制线程生命周期的场景
内容的提问来源于stack exchange,提问作者lucasllfortes
相关产品推荐
相关产品推荐

