我将尝试解释我的程序曾经做过什么以及我要改变的内容:
我有这个函数在MainWindow类的主线程上点击按钮运行:public QMainWindow:
该函数如下所示,并在另一个文件中指定:
void MakeMeshStructure(MeshStructureLayers layers,
Handle_AIS_InteractiveContext theContext,
Handle_TDocStd_Document aDoc,
MyMesh &mesh,
int detail_vertex,
double insulation_thickness,
OpenMesh::VPropHandleT<MyMesh::Scalar> _max_beam_offset);
}
它的作用是:它适用于网格,并为网格的每个顶点,面和边创建几何。使用上下文显示此几何体。这个过程需要很长时间(30分钟)并阻止gui。
我想做的是拥有与QThread :: idealThreadCount()一样多的线程,并在计算并使其更快时释放gui。 (这是正确的想法吗?)
我想将我的网格划分为相等的部分并将此范围的顶点传递给我的函数(上图),以便仅对一个顶点范围进行单独处理。
我有一个问题,想弄清楚如何传递这些数据并使其线程安全。 我知道很多代码,但这是我尝试解决它:
问题是以正确的方式获取所有数据并使线程正常工作。我在哪里必须使用互斥锁。在主线程执行线程时可以写入的每个数据?非常困惑。 TY
编辑:
我编辑了我的代码:http://pastebin.com/u/mzagar 我创建了一个struct cadData来传递数据。这就是我启动线程的方式:
connect(this, SIGNAL(startMake1(cadData)), cThreads.at(0), SLOT(MakeMesh(cadData)));
//...
cThreads.at(0)->moveToThread(threads.at(0));
//...
threads.at(0)->start();
//...
emit startMake1(aCadDatas.at(0));
//...
问题是线程似乎不能同时工作,而且gui冻结。流程如下:
任何想法为什么?
EDIT2:
通过将其移动到类构造函数中删除了同一线程的多次运行:
connect(this, SIGNAL(startMake1(cadData)), cThreads.at(0), SLOT(MakeMesh(cadData)));
//...
cThreads.at(0)->moveToThread(threads.at(0));
//...
threads.at(0)->start();
答案 0 :(得分:2)
由于您正在使用QThread,因此您可以避免使用Qt的线程安全插槽和信号机制来明确使用互斥锁,以便为您完成工作。您基本上将需要发送到线程的数据打包到对象中,然后发出一个信号,将该对象作为参数。该线程将在插槽中接收该对象的副本(之前已连接到您的信号),然后开始使用该数据。要将数据从工作线程返回到主线程,您可以反过来再次执行相同的操作。 Here's一篇包含一些示例代码的文章。
答案 1 :(得分:0)
添加到Jeremy的答案:您可以通过在QObject之间发送事件而不是使用信号槽机制来做同样的事情。使用最方便的选择。
关键是要利用Qt的内置事件循环互斥锁。当您向生活在与发送方不同的线程中的对象发送信号时,信号将转换为QMetaCallEvent并发布到接收QObject的事件队列中。当然,这是以线程安全的方式完成的,所有人必须做的就是利用它。发送显式事件的方式相同。在接收器所在的线程中旋转的事件循环只是选择QMetaCallEvents并相应地执行槽调用,或者将事件分派给customEvent()
方法的实现。
当你启动原始QThread
时,run()
方法的默认实现会旋转一个事件循环。您会注意到这样的线程实际上是空闲的并且不消耗任何CPU资源:事件队列为空,并且事件循环被阻塞,等待某人将事件发布到其队列。将一些QObject移动到这样的线程后,排队的信号槽交付将通过该线程的事件循环完成。无论是GUI线程还是任何其他线程,它的工作方式都相同。在接收事件或排队信号时,GUI线程没有任何特殊之处。