如果我不使用 deletelater 删除 qthread 会怎样?
what happens if i don't use deletelater for deleting qthread?
我正在尝试将 Qthread 与对象一起使用。为此,编写了这段代码:
QThread *thread1 = new QThread();
serialclass *obje = new serialclass();
void MainWindow::on_pushButton_baglan_clicked()
{
obje->moveToThread(thread1);
connect(thread1,SIGNAL(started()),obje,SLOT(baglan()), Qt::UniqueConnection);
connect(obje,SIGNAL(finished()),thread1,SLOT(quit())); //end of the baglan function finished() signal is emitted.
thread1->start();
}
我的代码有效。但我使用的是 quit(),而不是 deletelater()。可以多次按下按钮。第一个问题是,这种方法是否正确?我的第二个问题是如果我多次按下按钮会发生什么。有很多线程吗?是每次创建一个线程吗?
这很好。您应该明白您在做什么以及为什么这样做:代码及其目的应该来自于您并来自于这样的理解。
当您多次按下按钮时,应用程序可能处于以下两种状态之一:
线程已经完成:obje->thread() == nullptr
,您正在重新启动线程 - 它会正常工作。
线程仍然是 运行: obje->thread() == thread1
并且 moveToThread
和 thread1->start()
什么都不做。
唉,停止线程没有意义。它有一个事件循环,在新事件到达之前一直处于阻塞状态,这不像空闲 QThread
正在用完任何 CPU。启动一个线程是昂贵的:它创建一个新的本机线程。完成的线程不复存在:是的,您仍然有一个 QThread
,但这就像拥有一个已关闭文件的句柄。 QThread
毕竟是一个线程句柄。
您应该按值保留您的成员,而不是按指针 - 这避免了通过点额外间接的愚蠢过早悲观。您可以提前设置所有连接。您不需要 on_pushButton_baglan_clicked()
插槽:您可以将按钮直接与 SerialClass
实例连接。您还应该使用可安全破坏的 QThread
派生的 class。
您的代码如下所示。编译器将为您生成一个适当的 resource-deallocating 析构函数。这是编译器的工作,它永远不会让你在这项工作中失败——而人类开发人员很容易失败。因此,您应该充分利用 RAII,因为它将一项琐碎的手动工作转移到机器上,机器可以完美地完成它,而且几乎什么都不做:)
// MyWindow.h
#include <QMainWindow>
#include <QThread>
#include "SerialClass.h"
#include "ui_MyWindow.h"
class MyWindow : public QMainWindow {
Q_OBJECT
class SafeThread : public QThread {
using QThread::run; // final
public:
~SafeThread() { quit(); wait(); }
} m_serialThread;
SerialClass m_serial;
Ui::MyWindow ui;
public:
MyWindow(QWidget * parent = nullptr);
};
// MyWindow.cpp
#include "MyWindow.h"
MyWindow::MyWindow(QWidget * parent) :
QMainWindow{this}
{
ui.setupUi(this);
connect(ui.pushButton_baglan, &QPushButton::clicked,
&m_serial, &SerialClass::baglan);
m_serial.moveToThread(&m_serialThread);
m_serialThread.start();
}
如果您不希望所有实施细节都存在于 MyWindow
的 header 中,您 should use a PIMPL.
我正在尝试将 Qthread 与对象一起使用。为此,编写了这段代码:
QThread *thread1 = new QThread();
serialclass *obje = new serialclass();
void MainWindow::on_pushButton_baglan_clicked()
{
obje->moveToThread(thread1);
connect(thread1,SIGNAL(started()),obje,SLOT(baglan()), Qt::UniqueConnection);
connect(obje,SIGNAL(finished()),thread1,SLOT(quit())); //end of the baglan function finished() signal is emitted.
thread1->start();
}
我的代码有效。但我使用的是 quit(),而不是 deletelater()。可以多次按下按钮。第一个问题是,这种方法是否正确?我的第二个问题是如果我多次按下按钮会发生什么。有很多线程吗?是每次创建一个线程吗?
这很好。您应该明白您在做什么以及为什么这样做:代码及其目的应该来自于您并来自于这样的理解。
当您多次按下按钮时,应用程序可能处于以下两种状态之一:
线程已经完成:
obje->thread() == nullptr
,您正在重新启动线程 - 它会正常工作。线程仍然是 运行:
obje->thread() == thread1
并且moveToThread
和thread1->start()
什么都不做。
唉,停止线程没有意义。它有一个事件循环,在新事件到达之前一直处于阻塞状态,这不像空闲 QThread
正在用完任何 CPU。启动一个线程是昂贵的:它创建一个新的本机线程。完成的线程不复存在:是的,您仍然有一个 QThread
,但这就像拥有一个已关闭文件的句柄。 QThread
毕竟是一个线程句柄。
您应该按值保留您的成员,而不是按指针 - 这避免了通过点额外间接的愚蠢过早悲观。您可以提前设置所有连接。您不需要 on_pushButton_baglan_clicked()
插槽:您可以将按钮直接与 SerialClass
实例连接。您还应该使用可安全破坏的 QThread
派生的 class。
您的代码如下所示。编译器将为您生成一个适当的 resource-deallocating 析构函数。这是编译器的工作,它永远不会让你在这项工作中失败——而人类开发人员很容易失败。因此,您应该充分利用 RAII,因为它将一项琐碎的手动工作转移到机器上,机器可以完美地完成它,而且几乎什么都不做:)
// MyWindow.h
#include <QMainWindow>
#include <QThread>
#include "SerialClass.h"
#include "ui_MyWindow.h"
class MyWindow : public QMainWindow {
Q_OBJECT
class SafeThread : public QThread {
using QThread::run; // final
public:
~SafeThread() { quit(); wait(); }
} m_serialThread;
SerialClass m_serial;
Ui::MyWindow ui;
public:
MyWindow(QWidget * parent = nullptr);
};
// MyWindow.cpp
#include "MyWindow.h"
MyWindow::MyWindow(QWidget * parent) :
QMainWindow{this}
{
ui.setupUi(this);
connect(ui.pushButton_baglan, &QPushButton::clicked,
&m_serial, &SerialClass::baglan);
m_serial.moveToThread(&m_serialThread);
m_serialThread.start();
}
如果您不希望所有实施细节都存在于 MyWindow
的 header 中,您 should use a PIMPL.