这是使用 QThread 的正确方法吗?

Posted

技术标签:

【中文标题】这是使用 QThread 的正确方法吗?【英文标题】:Is this the correct way to use a QThread? 【发布时间】:2015-03-13 02:14:15 【问题描述】:

我正在查看一些 github 项目,其中一个项目通过以下方式完成了 UDPlink, 首先它继承 QThread 来创建一个类UDPLink:public QThread 它的构造函数和解构函数是这样的:

UDPLink::UDPLink(UDPConfiguration* config)
    : _socket(NULL)
    , _connectState(false)

    Q_ASSERT(config != NULL);
    _config = config;
    _config->setLink(this);

    // We're doing it wrong - because the Qt folks got the API wrong:
    // http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
    moveToThread(this);

    // Set unique ID and add link to the list of links
    _id = getNextLinkId();
    qDebug() << "UDP Created " << _config->name();


UDPLink::~UDPLink()

    // Disconnect link from configuration
    _config->setLink(NULL);
    _disconnect();
    // Tell the thread to exit
    quit();
    // Wait for it to exit
    wait();
    this->deleteLater();

虽然代码确实可以编译和工作,但我想知道这种使用 QThread 的方式是否正确?

【问题讨论】:

【参考方案1】:

QThread 的 Qt 文档描述了使用 QThread 完成线程的两种方式。子类化 QThread 是最初使用 QThread 的唯一方法。要以这种方式使用 QThread,请重写 run 方法,这是在新线程上运行的 QThread 方法。 QThread 应该被认为是一个线程管理器,而不是一个运行在单独线程本身上的对象。来自文档:

重要的是要记住 QThread 实例存在于旧的 实例化它的线程,而不是在调用 run() 的新线程中。 这意味着 QThread 的所有排队槽都将在旧的 线。因此,希望在新线程中调用槽的开发人员 必须使用工作对象方法;新插槽不应该 直接在子类 QThread 中实现。

子类化 QThread 时,请记住构造函数执行 在旧线程中,而 run() 在新线程中执行。如果是会员 从这两个函数访问变量,然后变量是 从两个不同的线程访问。检查这样做是否安全。

QThread documentation page

因为 QThread 是一个线程管理器类,所以创建了将对象移动到线程的解决方案。您提供的代码中的注释说明了此更改,因为该文章指出 moveToThread(this) 不是一个好习惯。

创建一个对象并将其移动到一个线程和子类化 QThread 都是使用 Qt 进行线程化的有效方法,正如文档现在明确指出的那样。如果您希望跨线程边界使用信号/槽连接,则使用工作对象方法有一个好处:工作对象将在其移动到的线程上拥有可用的槽。

【讨论】:

【参考方案2】:

正如 Qt 开发人员所建议的那样,您提到的代码不是使用 QThread 的正确方法。

推荐方式建议here。

来自 Post 的示例代码。

Producer producer;
Consumer consumer;
producer.connect(&consumer, SIGNAL(consumed()), SLOT(produce()));
consumer.connect(&producer, SIGNAL(produced(QByteArray *)), SLOT(consume(QByteArray *)));

// they both get their own thread
QThread producerThread;
producer.moveToThread(&producerThread);
QThread consumerThread;
consumer.moveToThread(&consumerThread);

// go!
producerThread.start();
consumerThread.start();

【讨论】:

以上是关于这是使用 QThread 的正确方法吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Qt 中正确终止 QThread?

QThread 与 QObject的关系?

重点:怎样正确的使用QThread类(注:包括推荐使用QThread线程的新方法QObject::moveToThread)

等待QThread时UI会阻塞/如何正确使用QThread

实现 QThread 的正确方法是啥...(请举例...)

qthreadnew不释放