C++ Qt 的简单多线程:我这样做对吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15216046/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:10:47  来源:igfitidea点击:

Simple multithreading with Qt: am I doing this right?

c++multithreadingqt4qthread

提问by evdc

I'm new to StackOverflow and wondering if I'm doing this right:

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

I'm writing a simple Qt application to test multi-threading (something I am also completely new to). I made a MainWindow that contains widgets, and a class MyThread that subclasses QThread and overrides the run() method.

我正在编写一个简单的 Qt 应用程序来测试多线程(我也是全新的)。我制作了一个包含小部件的 MainWindow 和一个 MyThread 类,它是 QThread 的子类并覆盖了 run() 方法。

The application simply displays two buttons, "Start Counter" and "Stop Counter", and a text field. When "start counter" is pressed, a worker thread is created and runs in the background, continuously incrementing a counter in a while loop and signaling the main thread (where the GUI is) with the updated value. When "Stop Counter" is pressed, a signal is sent to the main thread that stops the while loop, and the counter is stopped until "Start Counter" is pressed again.

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

This works perfectly fine ... but is it the best way? I'm new at this, and read a lot of people saying "don't subclass QThread" and other people saying "subclass QThread", and it's a little bit confusing. If this isn't the best way to implement this sort of thing (run a computationally-intensive loop in a background thread with "start" and "stop" buttons), what is? If I'm doing it wrong, how do I do it right? I don't want to learn the wrong way.

这工作得很好......但这是最好的方法吗?我是新手,读到很多人说“不要继承 QThread”,而其他人说“继承 QThread”,这有点令人困惑。如果这不是实现这类事情的最佳方式(在带有“开始”和“停止”按钮的后台线程中运行计算密集型循环),那是什么?如果我做错了,我该如何做对?我不想以错误的方式学习。

Thank you! And here's the code:

谢谢!这是代码:

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

我的线程.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

主窗口.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);
}

回答by ixSci

Most of the time QThread sub-classing is a wrong way to do threading in Qt. I suggest you to read an article about threads, event loops and otherwhich could give you an idea how to use threads in Qt in a better way. But do not listen to anyone who arguing that there is the only one right way to use QThread. There are 2 ways and while subclassing is not needed in general it could be useful sometimes. You just need to use non-subclassing way until you really need to subclass. In your particular case you don't need subclassing.

大多数时候 QThread 子类化是在 Qt 中进行线程化的错误方法。我建议你阅读一篇关于线程、事件循环和其他文章,它可以让你了解如何更好地在 Qt 中使用线程。但是不要听任何人说只有一种正确的方式来使用 QThread。有两种方法,虽然通常不需要子类化,但有时它可能很有用。您只需要使用非子类化方式,直到您真正需要子类化。在您的特定情况下,您不需要子类化。

回答by Aham

Replace sleep(1/1000);with msleep(100);Things will be just fine :)

sleep(1/1000);msleep(100);东西替换就好了:)