16、Qt线程(一):继承QThread,重写run

一、说明

Qt提供了3个类4种方式创建线程:

1、QThread

①继承QThread类,重写run()函数

②继承QObject类,使用moveToThread()函数

2、使用QtConCurrent并发模块的run()函数

3、继承QRunnable类

二、功能说明

1、通过继承QThread,重写run的方式实现多线程

2、点击“开始”按钮启动子线程,同时通过信号槽的方式给子线程发送“开始”字符串;

3、子线程每隔1秒向主线程发送累加数;

4、点击"停止"按钮,通过函数调用的方式停止子线程;

5、注:

①子线程构造函数、被主线程调用的函数(stop())和信号槽方式调用的函数(doSendData())都是在主线程

②只有run()和run()调用的函数showValue()在子线程

三、项目创建

1、新建Qt Widgets Application应用,名称为ThreadRun,基类选择QMainWindow;

2、mainwindow.ui中放入两个Push Button按钮,第一个text改为“开始”,objectNme改为startPushButton,第二个text改为“停止”,objectNme改为stopPushButton

3、添加新的C++类,名称为MyThread,基类设置为QThread

四、代码演示

1、mythread.h代码
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
#include <QThread>

class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = nullptr);

public slots:
    void stop(); //线程停止

    void doSendData(QString); //接收主线程发送的字符串

protected:
    void run(); //线程启动函数

signals:
    void sendValue(int); //给主线程发送累加数

private slots:
    void showValue(); //显示累加数

private:
    volatile bool stopped; //线程停止标识

    int value; //累加数
};

#endif // MYTHREAD_H

2、mythread.cpp代码

#include "mythread.h"
#include <QDebug>

MyThread::MyThread(QObject *parent) : QThread(parent)
{
    stopped = false;
    qDebug() << "创建 子线程id:" << QThread::currentThreadId();
}

/**
* @brief MyThread::stop 线程停止
*/
void MyThread::stop()
{
    stopped = true;
    qDebug() << "stop 子线程id:" << QThread::currentThreadId();
}

/**
* @brief MyThread::doSendData 接收显示主线程发送的字符串
* @param str
*/
void MyThread::doSendData(QString str)
{
    qDebug() << str << "doSendData 子线程id:" << QThread::currentThreadId();
}

/**
* @brief MyThread::run 子线程开始,自动调用run()函数
*/
void MyThread::run()
{
    value = 0;

    qDebug() << "run 子线程id:" << QThread::currentThreadId();
    while(!stopped)
    {
        showValue();
        msleep(1000); //延迟1秒
    }
    stopped = false;
}

/**
* @brief MyThread::showValue 显示并给主线程发送累加数
*/
void MyThread::showValue()
{
    qDebug() << value << "show子线程id:"<< QThread::currentThreadId();

    emit sendValue(value); //数据发送给主线程
    value++;
}

3、mainwindow.h代码

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "mythread.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals:
    void sendData(QString); //给子线程发送字符串

private slots:
    void on_startPushButton_clicked();

    void on_stopPushButton_clicked();

    void doSendValue(int); //接收子线程发送的累加数

private:
    Ui::MainWindow *ui;

    MyThread *m_myThread; //子线程对象
};

#endif // MAINWINDOW_H

4、mainwindow.cpp代码

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qDebug() << "主线程id:" << QThread::currentThreadId();

    m_myThread = new MyThread(this);
    //接收子线程数据
    connect(m_myThread, &MyThread::sendValue, this, &MainWindow::doSendValue);
    //给子线程发送数据
    connect(this, &MainWindow::sendData, m_myThread, &MyThread::doSendData);

    ui->startPushButton->setEnabled(true);
    ui->stopPushButton->setEnabled(false);
}

MainWindow::~MainWindow()
{
    if(m_myThread->isRunning())
    {
        m_myThread->stop();
    }
    m_myThread->quit(); //将子线程停止
    m_myThread->wait(); //等待子线程的运行结束后再停止

    delete ui;
}

/**
* @brief MainWindow::on_startPushButton_clicked 线程开始
*/
void MainWindow::on_startPushButton_clicked()
{
    emit sendData("开始");

    qDebug() << "主线程 startButtonid:" << QThread::currentThreadId();

    m_myThread->start(); //子线程开始,自动调用run()函数

    ui->startPushButton->setEnabled(false);
    ui->stopPushButton->setEnabled(true);
}

/**
* @brief MainWindow::on_stopPushButton_clicked 线程停止
*/
void MainWindow::on_stopPushButton_clicked()
{
    qDebug() << "主线程 stopButtonid:" << QThread::currentThreadId();
    if(m_myThread->isRunning())
    {
        m_myThread->stop();
        ui->startPushButton->setEnabled(true);
        ui->stopPushButton->setEnabled(false);
    }
}

/**
* @brief MainWindow::doSendValue 接收子线程发送的累加数
* @param value
*/
void MainWindow::doSendValue(int value)
{
    qDebug() << value << "doSendValue 线程id:"<< QThread::currentThreadId();
}

五、运行测试

先点击开始,一会再点击停止,输出框输出如下内容,根据线程id来区分不同的线程

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用 Qt 线程和 Modbus 库实现访问 Modbus 485 读写仪器仪表参数的 C++ 代码示例,不采用继承 QThread 重写 run 的方法实现: ```c++ // modbusworker.h #ifndef MODBUSWORKER_H #define MODBUSWORKER_H #include <QObject> #include <QModbusDevice> #include <QModbusTcpClient> class ModbusWorker : public QObject { Q_OBJECT public: explicit ModbusWorker(QObject *parent = nullptr); void setConnectionParameters(QString host, quint16 port); void setDeviceAddress(int address); bool connectDevice(); void readData(int startAddress, int numberOfValues); void writeData(int startAddress, int value); signals: void dataRead(QVector<quint16> data); void dataWritten(); private: QModbusDevice *modbusDevice; QString connectionHost; quint16 connectionPort; int deviceAddress; }; #endif // MODBUSWORKER_H ``` ```c++ // modbusworker.cpp #include "modbusworker.h" ModbusWorker::ModbusWorker(QObject *parent) : QObject(parent) { modbusDevice = new QModbusTcpClient(this); } void ModbusWorker::setConnectionParameters(QString host, quint16 port) { connectionHost = host; connectionPort = port; } void ModbusWorker::setDeviceAddress(int address) { deviceAddress = address; } bool ModbusWorker::connectDevice() { if (!modbusDevice) return false; modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, connectionHost); modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, connectionPort); modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, "COM1"); modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, "EvenParity"); modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, 9600); modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, 8); modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, 1); modbusDevice->setTimeout(1000); modbusDevice->setNumberOfRetries(3); if (!modbusDevice->connectDevice()) { return false; } return true; } void ModbusWorker::readData(int startAddress, int numberOfValues) { if (!modbusDevice) return; if (auto *reply = modbusDevice->sendReadRequest(QModbusDataUnit(QModbusDataUnit::HoldingRegisters, startAddress, numberOfValues), deviceAddress)) { if (!reply->isFinished()) { connect(reply, &QModbusReply::finished, this, [=]() { if (reply->error() == QModbusDevice::NoError) { emit dataRead(reply->result().values()); } reply->deleteLater(); }); } else { delete reply; } } else { emit dataRead(QVector<quint16>()); } } void ModbusWorker::writeData(int startAddress, int value) { if (!modbusDevice) return; if (auto *reply = modbusDevice->sendWriteRequest(QModbusDataUnit(QModbusDataUnit::HoldingRegisters, startAddress, 1), QVector<quint16>{static_cast<quint16>(value)}, deviceAddress)) { if (!reply->isFinished()) { connect(reply, &QModbusReply::finished, this, [=]() { if (reply->error() == QModbusDevice::NoError) { emit dataWritten(); } reply->deleteLater(); }); } else { delete reply; } } else { emit dataWritten(); } } ``` ```c++ // mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "modbusworker.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_connectPushButton_clicked(); void on_readPushButton_clicked(); void on_writePushButton_clicked(); void on_dataRead(QVector<quint16> data); void on_dataWritten(); private: Ui::MainWindow *ui; ModbusWorker *modbusWorker; }; #endif // MAINWINDOW_H ``` ```c++ // mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include <QMessageBox> #include <QThread> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , modbusWorker(new ModbusWorker(this)) { ui->setupUi(this); connect(modbusWorker, &ModbusWorker::dataRead, this, &MainWindow::on_dataRead); connect(modbusWorker, &ModbusWorker::dataWritten, this, &MainWindow::on_dataWritten); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_connectPushButton_clicked() { if (ui->tcpConnectionRadioButton->isChecked()) { modbusWorker->setConnectionParameters(ui->hostLineEdit->text(), ui->portSpinBox->value()); } else if (ui->serialConnectionRadioButton->isChecked()) { // Set serial connection parameters } modbusWorker->setDeviceAddress(ui->deviceAddressSpinBox->value()); if (!modbusWorker->connectDevice()) { QMessageBox::warning(this, "Error", "Unable to connect to Modbus device."); } } void MainWindow::on_readPushButton_clicked() { modbusWorker->readData(ui->startAddressSpinBox->value(), ui->numberOfValuesSpinBox->value()); } void MainWindow::on_writePushButton_clicked() { modbusWorker->writeData(ui->startAddressSpinBox->value(), ui->writeValueSpinBox->value()); } void MainWindow::on_dataRead(QVector<quint16> data) { // Process read data } void MainWindow::on_dataWritten() { // Process write data } ``` 在主界面中,通过连接不同的按钮和输入框,调用 ModbusWorker 类中的函数,实现连接 Modbus 设备、读取数据、写入数据等操作。而 ModbusWorker 类中的函数则使用 Qt Modbus 库提供的类和函数,实现连接 Modbus 设备、读写数据等操作,同时使用信号与槽机制将数据传递到主线程进行处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值