Qt通信线程,应用程序设计

时间:2015-08-21 09:38:11

标签: qt

我正在开发一个可以进行TCP通信,使用数据库并具有GUI(非常常见)的应用程序。在互联网上试验数据库时,我注意到GUI的响应速度慢,这促使使用线程来处理后端。我现在正在玩这个,并考虑完整的应用程序重新设计,以充分解决这个问题。因此,我想要分离GUI(从QMainWindow派生的类)和后端内容(从QObject派生的域类)。这个域类看起来像(我这样说是因为我显然不是模式的权威 - 总是学习)门面模式。我们的想法是在main函数中构造两个对象,然后将DomainClass的指针传递给MainWindow,即MainWindow(DomainClass * domain)。

然后是这个问题的重点。我想成像在域中构建许多(实际上不是那么多)对象,使它们通过信号/插槽机制进行通信。如下所示:

QThread* threadDB = new QThread;
m_database = new Database;
m_database->moveToThread(threadDB);
threadDB->start();

QThread* threadTM = new QThread;
m_tm = new TM;
connect(m_database, &Database::dbConnected, m_tm, &TM::onDbConnected);
m_tm->moveToThread(threadTM);
connect(threadTM, &QThread::started, m_tm, &TM::init);
threadTM->start();

但我得到以下内容:

QObject::connect: Cannot queue arguments of type 'QSqlDatabase'
(Make sure 'QSqlDatabase' is registered using qRegisterMetaType().)

我已经注意到如果我将m_tm留在线程之外它可以正常工作。如下所示:

QThread* threadDB = new QThread;
m_database = new Database;
m_database->moveToThread(threadDB);
threadDB->start();

m_tm = new TM;
connect(m_database, &Database::dbConnected, m_tm, &TM::onDbConnected);

这个设计合理吗?可以考虑哪些替代方案?

2 个答案:

答案 0 :(得分:1)

有两个问题。首先,运行时错误会告诉您究竟出了什么问题。您正在尝试按值传递数据库实例。用指针传递它。 Qt元类型系统知道如何处理这样的指针。

class Database {
  QSqlDatabase m_db;
  ...
public:
  Q_SIGNAL void dbConnected(QSqlDatabase*);
  ...
};

其次,您只能使用(doc)中创建的线程中的QSqlDatabase实例。因此没有必要将它传递给生活在不同线程中的对象。您应该将TM放在与Database对象相同的线程中,或者您应该让Database对象进一步封装数据库,只暴露一个信号槽接口,然后可以通过使用线程安全的排队调用从任何线程使用。

最后,你不应该使用每个对象的一个​​线程"图案。您必须能够在测量的支持下给出一个有用/有用的理由。线程的增加是一件坏事 - 你应该永远不会拥有核心。

答案 1 :(得分:0)

我正在为这个答案提供更多空间,但考虑到@Kuba Ober的回答,这可能很难。

要解决第二个问题(由@Kuba Ober指出),我可以将DomainClass完全移到另一个线程吗?在构造函数上编写以下代码:

QThread* thread = new QThread;
this->moveToThread(thread);
connect(thread, &QThread::started, this, &DomainClass::init);
thread->start();

并在init()上编写以下代码:

m_database = new Database;
m_tm = new TM;
connect(m_database, &Database::dbConnected, m_tm, &TM::onDbConnecte