gpt4 book ai didi

c++ - 以 "right"方式执行 QThread

转载 作者:行者123 更新时间:2023-11-30 05:48:29 26 4
gpt4 key购买 nike

在这个程序中,我按下“运行”按钮和一个 for 循环循环 100 次(延迟 100 毫秒)并在 txt 字段中打印循环计数

我已经使用派生自 QThread 的 MyThread 对象成功地完成了它。有用。我可以使用“停止”按钮中断循环。

但是严正警告从QThread派生对象是非常糟糕的。所以我做到了他们建议的另一种方式,“正确”的方式。

而且它不起作用。我可以在控制台上获取循环周期数,但不能输入文本框

在完成 100 个循环之前,“运行”按钮会下降并且不会再次出现。文本字段显示 99。

这是代码,我做错了什么?

// MyWidget.h   SF022

#ifndef MYWIDGET_H_
#define MYWIDGET_H_

#include <QtWidgets/QWidget>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QPushButton>

#include "../MyThread.h"
#include "../MyObject.h"
#include <QThread>

class MyWidget : public QWidget {

Q_OBJECT

public:
MyWidget(QWidget* parent = 0);
~MyWidget();

QPushButton* pbRun;
QPushButton* pbStop;
QPushButton* pbExit;
QLineEdit* txtCount;

QThread* cThread;

MyObject* myObject;

public slots:
void onNumberChanged(int);

private slots:
void pbRun_Slot();
void pbStop_Slot();
void pbExit_Slot();
};

#endif /* MYWIDGET_H_ */
------------------------------------------------
// MyWidget.cpp

#include "MyWidget.h"
#include "../K.h"
#include <iostream>

MyWidget::MyWidget(QWidget* parent) : QWidget(parent) {

pbRun = new QPushButton(this);
pbRun->setObjectName(QStringLiteral("pbRun"));
pbRun->setGeometry(QRect(20, 20, 80, 40));
pbRun->setText("Run");

connect(pbRun, SIGNAL(clicked()), this, SLOT(pbRun_Slot()));

pbStop = new QPushButton(this);
pbStop->setObjectName(QStringLiteral("pbStop"));
pbStop->setGeometry(QRect(20, 80, 80, 40));
pbStop->setText("Stop");

connect(pbStop, SIGNAL(clicked()), this, SLOT(pbStop_Slot()));

pbExit = new QPushButton(this);
pbExit->setObjectName(QStringLiteral("pbExit"));
pbExit->setGeometry(QRect(20, 140, 80, 40));
pbExit->setText("Exit");

connect(pbExit, SIGNAL(clicked()), this, SLOT(pbExit_Slot()));

txtCount = new QLineEdit(this);
txtCount->setGeometry(QRect(20, 200, 80, 40));
txtCount->setStyleSheet("QLineEdit{background: white;}");

// myObject holds the cycling mechanism
myObject = new MyObject(this);

// the myObject sends each new cycle number out here
connect(myObject, SIGNAL(numberChanged(int)), this, SLOT(onNumberChanged(int)));
}

MyWidget::~MyWidget() {
}

void MyWidget::pbRun_Slot() {

// start thread

cThread = new QThread(this);
myObject->doSetup(*cThread);
myObject->moveToThread(cThread);
cThread->start();
}

void MyWidget::pbStop_Slot() {

// stop the thread

myObject->Stop = true;
}

void MyWidget::pbExit_Slot() {

// a static pointer to the main window

(K::SfMainWin)->close();
}

// a slot
void MyWidget::onNumberChanged(int j) {

// output the cycle count to a text field
txtCount->setText(QString::number(j));
}
----------------------------------------------------------
// MyObject.h

#ifndef MYOBJECT_H_
#define MYOBJECT_H_

#include <QObject>
#include <QThread>

class MyObject : public QObject {

Q_OBJECT

public:
explicit MyObject(QObject* parent = 0);
~MyObject();

void doSetup(QThread&);

bool Stop;

signals:
void numberChanged(int);

public slots:
void doWork();
};

#endif /* MYOBJECT_H_ */
----------------------------------------------------------
// MyObject.cpp

#include "MyObject.h"
#include <QMutex>
#include <iostream>
#include "string.h"

MyObject::MyObject(QObject* parent) : QObject(parent) {

Stop = false;
}

MyObject::~MyObject() {

}

void MyObject::doSetup(QThread& cThread) {

Stop = false;

connect(&cThread, SIGNAL(started()), this, SLOT(doWork()));
}

void MyObject::doWork() {

for (int i = 0; i < 100; i++) {

QMutex mutex;

mutex.lock();
if (this->Stop) {

break;
}

// output into a text field
emit numberChanged(i);

// output on the console
std::cout << "running " << (QString::number(i)).toStdString() << std::endl;

mutex.unlock();

QThread::msleep(100);

}
}

最佳答案

myObject 从未移动到您创建的线程。一切都在主线程中执行。因为

myObject = new MyObject(this);

要将 QObject 移动到另一个线程,he should not have a parent .如果确实如此,Qt 将悄悄地告诉您出了什么问题(通过在输出上打印,与不正确的连接相同)。框架设计是为了不对这种类型的警告感到 panic ......

应该是

myObject = new MyObject(0);

现在已经清除了,您的代码中还有其他缺陷。

  1. QMutex mutex; 是本地的,总是由同一个线程获取。这意味着他没有目的。相反,它应该是 MyObject
  2. 的私有(private)成员
  3. MyWidget::pbStop_Slot 应该是 MyObject 的方法,否则在访问 Stop 成员时会出现竞争条件。还记得上面的互斥量吗?是时候使用它了。顺便说一句,您的实现直接调用该方法,因为 cThread 的偶数循环只执行 doWork

    MyObject::pbStop_Slot()
    {
    mutex.lock()
    Stop = true;
    mutex.unlock()
    }
  4. 现在您的程序在技术上应该是正确的。但是你不能使用信号和槽很糟糕,因为你的线程被阻止执行 doWork。另外,我们可以对那个锁做点什么吗?事实上,是的。我要走的路是使用 Qtimer 作为心跳 ech 100ms 而不是让线程休眠。但是为了不改变你的代码,你可以直接使用 QAbstractEventDispatcher * QAbstractEventDispatcher::instance ( QThread * thread = 0 )

    MyObject::pbStop_Slot() //becomes a real slot again
    {
    // no more mutex
    Stop = true;
    }
    ....
    //this connection is changed
    connect(pbStop, SIGNAL(clicked()), myObject, SLOT(pbStop_Slot()));
    ....

    void MyObject::doWork() {

    for (int i = 0; i < 100; i++) {

    //no mutex
    if (this->Stop) {

    break;
    }

    // output into a text field
    emit numberChanged(i);

    // output on the console
    std::cout << "running " << (QString::number(i)).toStdString() << std::endl;

    //process events, to allow stop to be processed using signals and slots
    QAbstractEventDispatcher::instance(cThread)->processEvents();

    QThread::msleep(100);
    }

  5. 关于 processEvents警告。就像现在一样,如果用户在执行 dowork 时按下 run它将在自身内部调用。你现在有一个讨厌的代码。避免这种情况的一个简单方法是在 dowork 的开头放置一个被检查和设置的 bool 值。

    dowork(){
    if(isdoingwork)
    return;
    isdoingwork = true
    for(...

这是实现目标的穷人方式 reentrancy .您会在 Qt 文档中经常看到可重入一词。

祝你在多线程之旅中好运。

关于c++ - 以 "right"方式执行 QThread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28156859/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com