QT GUI冻结,即使我运行在单独的线程
QT GUI freezes even though Im running in separate thread
我有一个小的聊天应用程序,我使用SQLite数据库来存储所有的对话。我注意到应用程序会随机死机,然后我必须将其最小化或最大化以使其再次运行。我认为问题可能是SQLite选择/插入导致gui冻结。我决定尝试将所有SQLite方法移动到一个单独的线程中。
这样做后,应用程序仍然冻结。
一些可能值得知道的事情:
-
我直接在我的
MainWindow
中使用QTcpSocket
,但似乎在单独的线程中运行QTcpSocket
没有用处? -
我已经把SQLite方法分离成一个新的线程(见下面的实现)
-
我使用3
WebViews
来显示我的聊天消息,整个应用程序GUI是用这些WebViews
构建的
我下面的代码真的在一个单独的线程中运行吗?GUI仍然会死机。
My header file:
class dbThread : public QObject
{
Q_OBJECT
public:
dbThread(QObject* parent);
public slots:
bool openDB(QString agentID);
signals:
void clearPreviousHistory();
private:
QSqlDatabase db;
QHash<QString, QString> countries;
};
My cpp file:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QThread* thread = new QThread(this);
dbtrad = new dbThread(this);
dbtrad->moveToThread(thread);
dbtrad->openDB(userID);
connect(dbtrad, SIGNAL(clearPreviousHistory()), this, SLOT(clearHistoryV()));
thread->start();
}
dbThread::dbThread(QObject * parent): QObject(parent) {
}
bool dbThread::openDB(QString agentID) {
qDebug() << "OPEN DB FROM THREAD ";
// Find QSLite driver
db = QSqlDatabase::addDatabase("QSQLITE");
// ......
}
这是我如何从我的MainWindow
调用dbThread
方法:
dbtrad->getHistory(channelId);
编辑
新代码:// Start database thread
QThread* thread = new QThread(this);
dbtrad = new dbThread(this);
dbtrad->moveToThread(thread);
connect(this, SIGNAL(requestOpenDB(QString)), dbtrad, SLOT(openDB(QString)));
thread->start();
emit requestOpenDB(userID);
dbtrad->openDB(userID);
将像任何正常函数一样执行(为什么要这样?),在GUI线程。
moveToThread
允许在一个单独的线程中使用信号执行插槽。
如果你想在线程中执行openDB
,你可以使用
connect (thread, SIGNAL(started()), dbtrad, SLOT(openDBWithUIDAlreadySet()))
或
connect (this, SIGNAL(requestOpenDB(int)), dbtrad, SLOT(openDB(int)))
您需要使用现有的或额外的信号。Qthread::start()
发出started()
信号。你也可以定义
MainWindow{
signals:
void requestOpenDB(int);
void queryHistory(int channelid);
}
并使用
手动发出信号emit requestOpenDB(userID); //for openDB
emit queryHistory(channelId); // for getHistory
来自dbThread
对象的响应也需要使用连接到插槽的信号来给出。像一个通知。
-
QTcpSocket
确实不需要在一个单独的线程中 -
只要所有的数据库访问都是在创建数据库的线程中完成的,这也应该是没有问题的
-
现在到有趣的部分:我认为你在主线程中创建数据库…通过调用
dbtrad->openDB(userId)
是的,所以qt moveToThread()
不做你期望它做的事情。你在主线程中调用的函数只会在主线程中执行。数据库访问导致GUI冻结。
moveToThread
只在一个单独的线程中移动"事件处理"。这意味着使用Qt::QueuedConnection
连接的dbThread
的任何插槽将在新线程中执行。
以下方法将只在你的主ui线程中执行getHistory()
方法。您需要在主线程中创建一个信号,并使getHistory()
成为dbThread
类的插槽。然后将两者连接起来。
阅读文档和日志是必要的!!
在日志中你有一个警告,如果对象有父线程,你不能移动到线程。文档也清楚地说:
更改此对象及其子对象的线程关联。的对象如果有父对象,则不能移动。事件处理将
正确的修复方法:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
thread = new QThread(this);
dbtrad = new dbThread(); // NO PARENT
dbtrad->moveToThread(thread);
// run object method in thread assigned to this object:
QMetaObject::invokeMethod(dbtrad, "openDB", Qt::QueuedConnection, Q_ARG(QString, userID));
connect(dbtrad, SIGNAL(clearPreviousHistory()), this, SLOT(clearHistoryV()));
thread->start();
}
MainWindow::~MainWindow()
{
dbtrad->deleteLater();
thread->quit();
thread->wait(5000); // wait max 5 seconds to terminate thread
}
- 如何检索指向在单独线程上运行的函数的移动指针?
- 运行单独的 cpp 文件,每个文件都有 main()
- Qt - 在单独的线程中运行函数
- 如何在单独的线程上运行函数(如果线程可用)
- 从单独的文件夹在 SUSE 上运行 GCC
- 尝试在 c++ 中运行单独的类与 c++ 中的代码
- 在单独的可执行文件中调用INSTANTIATE_TEST_CASE_P时,库中的TEST_P测试不会运行
- QTimer对象是否在单独的线程中运行?它的机制是什么
- 如何从安卓原生二进制文件运行单独的进程
- 在单独的线程中运行成员功能
- 从QT创建者运行的应用程序使用与单独运行时不同的库
- 使用局部全局变量在单独的线程中运行C函数
- C++ std::future在单独的内核上运行每个函数
- C++Qt在单独的过程中运行应用程序的各个部分
- maxi 和 min 时间,用于计算在 n 处进行六次单独运行的斐波那契数
- CLion在单独的系统终端中运行程序
- 需要有关在类之间共享变量的 OOP 设计的帮助,这些变量单独使用计时器运行
- C++二进制文件在使用valgrind运行时执行良好,但在单独运行此二进制文件时失败
- 在int main函数中编译并运行的循环在放入单独的函数时不会编译
- PC多线程性能和稳定性问题的简单基准测试.如何使每个线程在单独的核心上运行