嵌入式_晚风 2024-07-27 18:05 采纳率: 100%
浏览 5
已结题

使用QThread遇到的疑问

一个使用重载run()函数的子线程类,这个类中还有diceBegin()、dicePause()、stopThread() 函数用于线程控制,是由主线程调用的,
已知除了run()函数是在子线程中运行的,其他函数包括构造函数都是在主线程中运行的,那么,在主线程中调用线程控制函数diceBegin()、dicePause()、stopThread() 修改了一些变量的值,这些变量的值是怎么同步到子线程的 run() 函数中的?
对应于下面代码即如在主线程中修改了m_Paused的值,子线程中 run() 为什么会知道m_Paused值发生变化,原理是什么
QDiceThread.h:

#ifndef QDICETHREAD_H
#define QDICETHREAD_H

#include    <QThread>

class QDiceThread : public QThread
{
    Q_OBJECT
private:
    int     m_seq=0;//掷骰子次数序号
    int     m_diceValue;//骰子点数
    bool    m_Paused=true; //掷一次骰子
    bool    m_stop=false; //停止线程
protected:
    void    run() Q_DECL_OVERRIDE;  //线程任务
public:
    QDiceThread();

    void    diceBegin();//掷一次骰子
    void    dicePause();//暂停
    void    stopThread(); //结束线程
signals:
    void    newValue(int seq,int diceValue); //产生新点数的信号
};

#endif // QDICETHREAD_H

QDiceThread.cpp:

#include "qdicethread.h"
#include    <QTime>
#include <QDebug>

QDiceThread::QDiceThread()
{
    qDebug() << "QDiceThread constructor id =" << QThread::currentThreadId();
}

void QDiceThread::diceBegin()
{ //开始掷骰子
    qDebug() << "QDiceThread diceBegin id =" << QThread::currentThreadId();
    m_Paused=false;
}

void QDiceThread::dicePause()
{//暂停掷骰子
    m_Paused=true;
}

void QDiceThread::stopThread()
{//停止线程
    m_stop=true;
}

void QDiceThread::run()
{//线程任务
    m_stop=false;//启动线程时令m_stop=false
    m_seq=0; //掷骰子次数
    qsrand(QTime::currentTime().msec());//随机数初始化,qsrand是线程安全的
    qDebug() << "QDiceThread run id =" << QThread::currentThreadId();
    while(!m_stop)//循环主体
    {
        if (!m_Paused)
        {
            m_diceValue=qrand(); //获取随机数
            m_diceValue=(m_diceValue % 6)+1;
            m_seq++;
            emit newValue(m_seq,m_diceValue);  //发射信号
        }
        msleep(500); //线程休眠500ms
    }

//  在  m_stop==true时结束线程任务
    quit();//相当于  exit(0),退出线程的事件循环
}

dialog.cpp:

#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>

void Dialog::closeEvent(QCloseEvent *event)
{ //窗口关闭事件,必须结束线程
    if (threadA.isRunning())
    {
        threadA.stopThread();
        threadA.wait();
    }
    event->accept();
}

Dialog::Dialog(QWidget *parent) : QDialog(parent),  ui(new Ui::Dialog)
{//构造函数
    ui->setupUi(this);
    qDebug() << "Dialog constructor id =" << QThread::currentThreadId();
    connect(&threadA,SIGNAL(started()),this,SLOT(onthreadA_started()));
    connect(&threadA,SIGNAL(finished()),this,SLOT(onthreadA_finished()));

    connect(&threadA,SIGNAL(newValue(int,int)),this,SLOT(onthreadA_newValue(int,int)));
}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::onthreadA_started()
{//线程的started()信号的响应槽函数
    ui->LabA->setText("Thread状态:thread started");
}

void Dialog::onthreadA_finished()
{//线程的 finished()信号的响应槽函数
    ui->LabA->setText("Thread状态:thread finished");
}

void Dialog::onthreadA_newValue(int seq,int diceValue)
{//QDiceThread的newValue()信号的响应槽函数,显示骰子次数和点数
    QString  str=QString::asprintf("第 %d 次掷骰子,点数为:%d",seq,diceValue);
    ui->plainTextEdit->appendPlainText(str);

    QPixmap pic; //图片显示
    QString filename=QString::asprintf(":/dice/images/d%d.jpg",diceValue);
    pic.load(filename);
    ui->LabPic->setPixmap(pic);
}

void Dialog::on_btnClear_clicked()
{ //清空文本 按钮
    ui->plainTextEdit->clear();
}

void Dialog::on_btnDiceEnd_clicked()
{//暂停 掷骰子按钮
    threadA.dicePause();
    ui->btnDiceBegin->setEnabled(true);
    ui->btnDiceEnd->setEnabled(false);
}

void Dialog::on_btnDiceBegin_clicked()
{//开始 掷骰子按钮
    threadA.diceBegin();
    ui->btnDiceBegin->setEnabled(false);
    ui->btnDiceEnd->setEnabled(true);
}

void Dialog::on_btnStopThread_clicked()
{//结束线程 按钮
    threadA.stopThread();//结束线程的run()函数执行
    threadA.wait();//

    ui->btnStartThread->setEnabled(true);
    ui->btnStopThread->setEnabled(false);

    ui->btnDiceBegin->setEnabled(false);
    ui->btnDiceEnd->setEnabled(false);
}

void Dialog::on_btnStartThread_clicked()
{//启动线程 按钮
    threadA.start();

    ui->btnStartThread->setEnabled(false);
    ui->btnStopThread->setEnabled(true);

    ui->btnDiceBegin->setEnabled(true);
    ui->btnDiceEnd->setEnabled(false);
}
  • 写回答

2条回答 默认 最新

  • 专家-司宇[在线] 2024-07-27 18:29
    关注

    引自免费微信小程序:皆我百晓生

    在Qt中,当您使用QThread创建线程时,子线程和主线程之间的数据共享和通信是通过一些特定方式实现的。关于您提到的QDiceThread类中变量在主线程和子线程间的同步问题,这里的关键是理解Qt的信号-槽机制和线程间的通信方式。

    在您的代码中,QDiceThread类继承自QThread。当您调用start()方法启动线程时,run()函数会在一个新的线程中执行。这意味着run()函数中的代码是在子线程中运行的,而类的其他成员函数(如diceBegin(), dicePause(), stopThread())是在主线程中运行的。

    关于变量同步的问题,Qt并没有自动的方式去同步这些变量。当您在主线程中调用diceBegin(), dicePause(), stopThread()等函数并改变成员变量(如m_Paused)的值时,这些改变并不会自动同步到子线程的run()函数中。但是,由于Qt的信号-槽机制是线程安全的,当您发出信号(如newValue)时,接收这个信号的槽函数(如onthreadA_newValue())会在接收信号的线程中执行,也就是说,onthreadA_newValue()会在子线程中执行。

    对于状态变量(如m_Pausedm_stop)的同步,您需要在子线程中定期检查这些变量的值。在run()函数中,您可以定期读取这些变量的值以检查它们是否已更改。例如,在循环体内加入检查点:

    void QDiceThread::run() {
        m_stop = false; // 启动线程时令m_stop=false
        m_seq = 0; // 掷骰子次数
        qsrand(QTime::currentTime().msec()); // 随机数初始化
    
        while(!m_stop) { // 循环主体
            // 检查是否暂停或停止
            if (m_Paused || m_stop) {
                // 根据需要处理暂停或停止的逻辑
                break; // 或者用其他方式结束循环
            }
            
            // 其他操作,如获取随机数等
            ...
            
            // 定期检查和更新变量值以实现同步
            if (needToUpdateVariables) { // 根据逻辑判断是否需要更新变量值
                // 更新变量的值并检查信号是否发出等逻辑...
            }
            
            msleep(500); // 线程休眠500ms后再次检查变量值和其他逻辑
        }
        // 结束线程任务...
    }
    

    通过这种方式,您可以实现主线程和子线程之间的通信和同步。请注意,这种方法需要您自己管理同步逻辑,确保线程安全地访问共享资源。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 8月4日
  • 已采纳回答 7月27日
  • 创建了问题 7月27日

悬赏问题

  • ¥15 ArcGIS批量裁剪
  • ¥15 labview程序设计
  • ¥15 为什么在配置Linux系统的时候执行脚本总是出现E: Failed to fetch http:L/cn.archive.ubuntu.com
  • ¥15 Cloudreve保存用户组存储空间大小时报错
  • ¥15 伪标签为什么不能作为弱监督语义分割的结果?
  • ¥15 编一个判断一个区间范围内的数字的个位数的立方和是否等于其本身的程序在输入第1组数据后卡住了(语言-c语言)
  • ¥15 游戏盾如何溯源服务器真实ip?
  • ¥15 Mac版Fiddler Everywhere4.0.1提示强制更新
  • ¥15 android 集成sentry上报时报错。
  • ¥50 win10链接MySQL