使用 Qt 的简单多线程:我这样做对吗?

Posted

技术标签:

【中文标题】使用 Qt 的简单多线程:我这样做对吗?【英文标题】:Simple multithreading with Qt: am I doing this right? 【发布时间】:2013-02-19 09:30:42 【问题描述】:

我是 *** 的新手,想知道我这样做是否正确:

我正在编写一个简单的 Qt 应用程序来测试多线程(我也完全不熟悉)。我创建了一个包含小部件的 MainWindow,以及一个子类 QThread 并覆盖 run() 方法的 MyThread 类。

应用程序只显示两个按钮,“开始计数器”和“停止计数器”,以及一个文本字段。当按下“启动计数器”时,会创建一个工作线程并在后台运行,在 while 循环中不断增加一个计数器,并用更新后的值向主线程(GUI 所在的位置)发出信号。当按下“停止计数器”时,会向主线程发送一个信号以停止 while 循环,并停止计数器,直到再次按下“启动计数器”。

这很好用……但这是最好的方法吗?我对此很陌生,并且读过很多人说“不要子类 QThread”和其他人说“子类 QThread”,这有点令人困惑。如果这不是实现这类事情的最佳方式(在带有“开始”和“停止”按钮的后台线程中运行计算密集型循环),那是什么?如果我做错了,我该如何做对?我不想学错。

谢谢!这是代码:

MyThread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QMutex>

class MyThread : public QThread

   Q_OBJECT

public slots:
    void stopRunning();

protected:
   virtual void run();

signals:
   void signalValueUpdated(QString);

private:
    bool isRunning;

;

MyThread.cpp

#include "MyThread.h"
#include <QString>

void MyThread::run()

    qDebug("Thread id inside run %d",(int)QThread::currentThreadId());

    static int value=0; //If this is not static, then it is reset to 0 every time this function is called.
    isRunning = 1;
    while(isRunning == 1)
    
        QString string = QString("value: %1").arg(value++);
        sleep(1/1000); //If this isn't here, the counter increments way too fast and dies, or something; the app freezes, anyway.

        emit signalValueUpdated(string);       
                


void MyThread::stopRunning()

    isRunning = 0;

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include "MyThread.h"

class MainWindow : public QWidget

  Q_OBJECT

  public:
    MainWindow(QWidget *parent = 0);

  private:
    //Widgets
    QHBoxLayout * boxLayout;
    QPushButton * startButton;
    QPushButton * stopButton;
    QLineEdit * lineEdit;

    MyThread thread;
;

#endif

MainWindow.cpp

#include "MainWindow.h"

MainWindow::MainWindow(QWidget *parent) : QWidget(parent)

    boxLayout = new QHBoxLayout(this);
    startButton = new QPushButton("Start Counter", this);
    stopButton = new QPushButton("Stop Counter", this);
    lineEdit = new QLineEdit(this);

    boxLayout->addWidget(startButton);
    boxLayout->addWidget(stopButton); 
    boxLayout->addWidget(lineEdit);

    qDebug("Thread id %d",(int)QThread::currentThreadId());

    //When the start button is pressed, invoke the start() method in the counter thread
    QObject::connect(startButton,SIGNAL(clicked()),&thread,SLOT(start()), Qt::QueuedConnection);

    //When the stop button is pressed, invoke the stop() method in the counter thread
    QObject::connect(stopButton,SIGNAL(clicked()),&thread,SLOT(stopRunning()), Qt::QueuedConnection);

    //When the counter thread emits a signal saying its value has been updated, reflect that change in the lineEdit field.
    QObject::connect(&thread,SIGNAL(signalValueUpdated(const QString&)),lineEdit,SLOT(setText(const QString&)), Qt::QueuedConnection);

【问题讨论】:

小心sleep(1/1000) 表示sleep(0) 要扩展@ixSci 的答案,请阅读以下链接。有一些微妙的陷阱:mayaposch.wordpress.com/2011/11/01/… 很好,谢谢!将其更改为睡眠(0.001)。 你仍然有 0。sleep 接受整数,我没有看到任何 sleep 接受小数。使用msleep(1)来实现你想要的。 【参考方案1】:

在大多数情况下,QThread 子类化是在 Qt 中进行线程化的错误方式。我建议您阅读article about threads, event loops and other,它可以让您了解如何以更好的方式在 Qt 中使用线程。但是不要听任何人争辩说只有一种正确的方法可以使用 QThread。有两种方法,虽然通常不需要子类化,但有时它可能很有用。您只需要使用非子类化方式,直到您真正需要子类化。在您的特定情况下,您不需要子类化。

【讨论】:

那么,使用子类化的缺点到底是什么? (即,为什么我应该使用它?)在我看来,这比创建一个单独的 QThread 和一个单独的工作线程然后执行 moveToThread() 要容易得多。至少,在使用子类化时更容易理解发生了什么。 @GijsvanOort,我上面提到的文章回答了你的问题。【参考方案2】:

sleep(1/1000); 替换为msleep(100); 一切都会好起来的:)

【讨论】:

以上是关于使用 Qt 的简单多线程:我这样做对吗?的主要内容,如果未能解决你的问题,请参考以下文章

Qt如何循环创建线程

QT多线程简单例子

使用 QtConcurrent 在 QT 中进行多线程

使用格式化日期排序,这样做对吗?

在 XML 中生成带有内置到期日期的简单许可证 - 我这样做对吗?

qt多线程中怎样锁定一个指定的变量?