Sas*_*asa 17 c++ qt multithreading qtsql
基于Qt文档:
只能在创建连接的线程中使用连接.不支持在线程之间移动连接或从其他线程创建查询.
困扰我的问题是,当我复制构造数据库实例时会发生什么.例如,这是主线程中的代码:
int main(int argc, char** argv) {
...
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "DB1");
db.setHostName("localhost");
...
Run Code Online (Sandbox Code Playgroud)
这是工作线程中的连接:
void MyThread::run() {
QSqlDatabase db(QSqlDatabase::database("DB1"));
if (db.open()) {
...
}
Run Code Online (Sandbox Code Playgroud)
这个线程是否安全?通常,这样的操作在C++中是安全的,但由于QT使用隐式共享和线程关联,我不再确定.
他们说:连接只能在创建它的线程中使用,但这意味着什么?QSqlDatabase :: addDatabase 是指创建连接的位置,还是实际调用open()函数时的位置.
更新:
在得到Laszlo Papp的回答,并最终查看Qt源代码之后,我必须说Qt的这部分设计看起来对我来说是有缺陷的.
如果我理解正确,QSqlDatabase使用隐式共享,但不幸的是它不是真正的隐式共享,因为QSqlDatabase实例的复制构造函数在需要时不会创建共享数据的新实例.更糟糕的是,您无法创建临时连接,而是必须使用静态方法addDatabase/removeDatabase,在这种情况下,您必须同步线程以避免名称冲突.
这当然使得在QtConcurrent中使用QSqlDatabase非常困难,特别是如果连接应该深埋在一些抽象之后.由于我们不知道代码将在哪个线程上运行,因此我们无法在两次调用之间保持连接打开.如果我们想要生成动态数量的任务,我们需要确保任务不使用相同的数据库名称.
所有这些让我对设计目标感到疑惑,以及隐式共享是否适合这种特殊情况.恕我直言,更好的解决方案是让复制构造函数真正做到这一点并为你制作一个连接副本.那些不想拥有私有/临时副本的人仍然可以使用addDatebase/removeDatabase,在这种情况下需要修改方法database()以返回引用.
您可以用于QSqlDatabase::cloneDatabase获取数据库的“真实”副本,该副本可以在任何线程中打开。
您需要在初始化克隆数据库的线程中执行此操作,但您可以将获得的尚未打开的数据库移动到任何线程并在那里使用它。
他们说:连接只能在创建它的线程中使用,但这意味着什么?QSqlDatabase :: addDatabase是指创建连接的位置,还是实际调用open()函数时的位置.
前者.有关详细信息,请参阅文档
QSqlDatabase类表示与数据库的连接.
QSqlDatabase类提供了通过连接访问数据库的接口.QSqlDatabase的实例表示连接.该连接通过一个受支持的数据库驱动程序提供对数据库的访问,这些驱动程序源自QSqlDriver.或者,您可以从QSqlDriver继承自己的数据库驱动程序.有关更多信息,请参见如何编写自己的数据库驱动程序.
通过调用静态addDatabase()函数之一来创建连接(即QSqlDatabase的实例)...
最后一句话应该清楚你的担忧.