qt - 为 Qt 工作线程打开和关闭数据库连接的正确方法是什么
问题描述
我正在处理一个我们想要在数据库表上异步执行INSERT
/DELETE
语句的场景(这是一个即发即弃的场景)。我打算简单地用相关数据触发一个信号,并让线程的事件循环处理每个信号,类似于以下示例:
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(signalSource, &SignalSource::dataReady, worker, &Worker::updateMyFancyTable);
workerThread.start();
只要线程正在运行,它就应该打开自己的数据库连接。我会这样做(当然,增加了错误处理):
connect(&workerThread, &QThread::started, worker, &Worker::establishDatabaseConnection);
当停止线程时,它应该完成它的工作,然后关闭数据库连接。
据我了解,在线程上调用quit()将首先处理所有剩余的信号(如果有),然后退出线程的事件循环。
在这种情况下如何正确关闭数据库连接?
- 在调用之前我会发出关闭连接的信号
quit()
吗? - 我是否在发出一次调用的主线程的插槽中关闭连接
QThread::finished
? - 还有什么?
解决方案
我认为这个讨论回答了你的一些问题:立即停止在 QThread.exit() 上处理事件队列。所以看起来是的,所有的插槽都是在线程退出之前执行的。建议的解决方案是使用 QThread::requestInterruption 并在您的插槽中测试 QThread::currentThread()->isInterruptionRequested() 。请注意,该插槽仍被多次调用,因此您必须返回,直到队列为空。
在您的情况下,您可以在中断请求后忽略呼叫并发出信号以关闭连接。所以选项1可能是一个解决方案。或者您甚至可以在 isInterruptionRequested() 第一次在您的插槽中返回 true 时关闭连接,但您可能必须处理空事件队列的情况并无论如何调用插槽。
选项 2 可能不是一个可行的解决方案,具体取决于您如何处理与数据库的连接:通常,该连接只能在创建它的线程中使用。Qt SQL 模块就是这种情况(https://doc.qt.io/qt-5/threads-modules.html#threads-and-the-sql-module)。您可以将 finished() 信号连接到在后台线程中执行的插槽,然后关闭那里的连接,但我对https://doc.qt.io/qt-5/qthread.html#finished的理解是可能是不可能的,因为“当这个信号发出时,事件循环已经停止运行”。奇怪的事情:我测试并在后台线程中调用了插槽......文档说“除了延迟删除事件”,所以在后台线程中调用了 dtor,这将是一个选项。
对于 QSqlDatabase(或以相同方式工作的连接),我更喜欢手动处理事件队列,以获得更多控制权。例如,创建一个消息队列,等待新请求的信号量并在 QThread 子类中处理这些请求。在 run() 方法中,首先创建连接,在执行期间使用,并在从 run() 方法返回之前关闭。run() 方法迭代直到请求中断。这使得对象独立,管理自己的数据库连接。这似乎更简单,特别是当您想同时查询数据库时。
推荐阅读
- r - Rolling Sum Dplyr
- javascript - 在 Node.js 中将 MATLAB 表文件加载为数组
- javascript - WebRTC 发送自定义字节音频/视频数据
- python - zxJDBC - 设置 oracle 驱动类路径
- c - 如何解决c中“字节交换操作”引入的污染标量覆盖问题
- javascript - 索引或大小为负数或大于允许的数量。源高度为 0。HTML5 画布和反应
- angular - 在不工作的孩子中使用lazyLoading进行路由 - 无法匹配路由
- angular - 基于角度 6 中选定的 mat-autocomplete 值的搜索表
- java - 检查 Firebase 云消息传递的新通知。(FCM)
- php - WooCommerce 输出破坏了我的代码 - 错误关闭的标签