我遇到了一些我不理解的Qt线程问题,在Windows 7上运行Qt5.6。一切都是使用MSYS2安装和构建的。
我创建了一个Server
对象,它代表远程客户端管理Device
对象。两者都是QObject
的子类。在Server
收到创建设备的客户端请求后,构建Device
并将Server
作为其父级。
但是当我在GDB中运行应用程序时,为this->parent()
调用Device
会返回一个NULL
指针,指示此对象没有父对象。此外,this->thread()
从Server
对象的线程返回不同的线程。并且在"Cannot create children for a parent that is in a different thread"
构造函数本身的某处打印了必要的QObject
警告。
尽管Device
对象的构造函数作为其父项传递Server
,但没有其他显式创建的线程。没有显式创建的QThread
对象,我只使用QCoreApplication::exec()
创建的默认事件循环。此外,在Linux或OS X上编译和运行它确认父设置正确,并且两个对象都在同一个线程中。
我理解为什么像setParent()
这样的调用或它的道德等价物会失败,以保持对象及其相应的事件循环在同一个线程中。但是看起来Device
对象的线程亲和性在某种程度上已经被构造函数调用时设置了。但是为什么首先有多个线程呢?为什么只在Windows上呢?为什么在一个看似随机的线程中创建对象,当它可以很好地使用我在构造函数中传递的父线程时?
编辑:
还有其他一些需要注意的事项。我不仅没有调用moveToThread()
或类似的东西,而且没有任何类型的并发性。这包括QRunnable
或QtConcurrent
模块中的任何内容。
实际上解决实际问题的另一件事,但我不明白,如果我编译发布,这就会消失。我一直在开发期间使用调试版本,这显然是奇怪的线程/父行为显示的唯一时间。当我运行发布版本时,一切都在游泳。这可能是我正在使用的GDB的MSYS2构建中的错误吗?也许在某种程度上Qt与GDB没有很好地协调(反之亦然)?
编辑2:
基于@Ben的评论,我在QObject
构造函数代码中找到了更深入的内容(找到here,它从821行开始。在第826行,最终函数{{1}调用,这是父和子的线程首先看起来不同的地方.Qt内部类QThreadData::current()
的静态函数QThreadData
(找到here)似乎查询线程 - 本地存储返回当前线程的索引,我认为,它看起来与父线程的索引不同。我不太了解Windows线程库,知道这是不是真的发生了什么,但在阅读{{基于1}}的代码版本,这是我最好的猜测。
此时我在兔子洞的距离很远,但似乎我的修正问题是:为什么current()
会从父母那里返回一个不同的线程?或者为什么包含这些数据的线程局部存储在构造父元素和调用子构造函数之间发生了变化?