线程:2种情况可能造成:QObject::startTimer: Timers cannot be started from another thread (***)

目录

2种情况可能造成:QObject::startTimer: Timers cannot be started from another thread

----------------------------------------------------------------

问题:不要随意将同类的文件,合并成一个文件。

将 timer()与非timer()文件合并在一起,在对非 timer()文件使用多线程时,就产生了本文的错误。

========================================

2种情况可能造成:QObject::startTimer: Timers cannot be started from another thread

一、分析 2 种情形,这里重现一下

1、一般情况

这种一般比较常见

1、创建自定义类型 MyTest

2、头文件 mytest.h

    #ifndef MYTEST_H
    #define MYTEST_H
     
    #include <QThread>
    #include <QTimer>
     
    class MyTest : public QThread
    {
        Q_OBJECT
    public:
        explicit MyTest(QObject *parent = nullptr);
     
    protected:
        virtual void run() override;
     
    signals:
     
    private:
        QTimer *m_timer;
     
    };

3、源文件 mytest.cpp

    #include "mytest.h"
     
    MyTest::MyTest(QObject *parent) : QThread(parent)
    {
        m_timer = new QTimer();
        start();
    }
     
    // 子线程
    void MyTest::run()
    {
        m_timer->start(100);
    }

调试结果

然后

至于为什么这样,它已经给出明确的提示

QTimer 不能不同线程中启动

解决方案也比较简单

把 QTimer 的操作都放在同一个线程即可

修改下源文件 mytest.cpp

    #include "mytest.h"
     
    MyTest::MyTest(QObject *parent) : QThread(parent)
    {
        start();
    }
     
    // 子线程
    void MyTest::run()
    {
        m_timer = new QTimer();
        m_timer->start(100);

    }

完成

2、其他情况

这种情况隐藏的深一点

我们使用一个串口类来演示

测试函数:主要功能是向串口里面写入数据

    void MyTest::onSaveDatas(QByteArray buf)
    {
        // 打开串口
        if(m_serial == nullptr){
            m_serial = new QSerialPort();
            m_serial->setPortName("COM1");
            m_serial->open(QIODevice::ReadWrite);
        }
     
        // 写入串口
        m_serial->write(buf);
    }

调用方式

        MyTest *obj = new MyTest();       // 创建对象 obj
        QThread *thread1 = new QThread(); // 创建线程 thread1
        obj->moveToThread(thread1);       // 将对象移动到 thread1 子线程中
        thread1->start();                 // 开启 thread1 子线程
     
        // 信号槽连接
        connect(this, &Widget::sig_save_data, obj, &MyTest::onSaveDatas);
     
        emit sig_save_data("123"); // 发射写信号
        QThread::msleep(1000);     // 测试使用,暂停一会儿
        obj->onSaveDatas("123");   // 调用写入

 调试结果

 可以看到,我们并没有使用 QTimer

它却产生了这样的信息

会给我们带来不明确的方向,花费大量的时间去 debug

还可能找不到问题点

。。。

那如何修正

因对象已经被移动到子线程

这时候

推荐使用信号槽的方式去交互

尽量不要直接以调用方式去使用

修改一下

        emit sig_save_data("123"); // 发射写信号
        QThread::msleep(1000);     // 测试使用,暂停一会儿
        //obj->onSaveDatas("123");   // 调用写入  ***不使用这种方式

 这样它就不会产生那样的信息啦

***完整工程代码

mytest.h

    #ifndef MYTEST_H
    #define MYTEST_H
     
    #include <QObject>
    #include <QtSerialPort/QSerialPort>
     
    class MyTest : public QObject
    {
        Q_OBJECT
    public:
        explicit MyTest(QObject *parent = nullptr);
     
    public:
        void onSaveDatas(QByteArray buf);
     
    signals:
     
    private:
        QSerialPort *m_serial = nullptr;
     
    };
     
    #endif // MYTEST_H

mytest.cpp

    #include "mytest.h"
     
    #include <QThread>
     
    MyTest::MyTest(QObject *parent) : QObject(parent)
    {
     
    }
     
    void MyTest::onSaveDatas(QByteArray buf)
    {
        // 打开串口
        if(m_serial == nullptr){
            m_serial = new QSerialPort();
            m_serial->setPortName("COM1");
            m_serial->open(QIODevice::ReadWrite);
        }
     
        // 写入串口
        m_serial->write(buf);
    }
     

widget.h  

    #ifndef WIDGET_H
    #define WIDGET_H
     
    #include <QWidget>
     
    QT_BEGIN_NAMESPACE
    namespace Ui { class Widget; }
    QT_END_NAMESPACE
     
    class Widget : public QWidget
    {
        Q_OBJECT
     
    public:
        Widget(QWidget *parent = nullptr);
        ~Widget();
     
    signals:
        void sig_save_data(QByteArray buf);
     
    private:
        Ui::Widget *ui;
    };
    #endif // WIDGET_H

 widget.cpp

    #include "widget.h"
    #include "ui_widget.h"
     
    #include <QThread>
    #include "mytest.h"
     
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::Widget)
    {
        ui->setupUi(this);
     
        MyTest *obj = new MyTest();       // 创建对象 obj
        QThread *thread1 = new QThread(); // 创建线程 thread1
        obj->moveToThread(thread1);       // 将对象移动到 thread1 子线程中
        thread1->start();                 // 开启 thread1 子线程
     
        // 信号槽连接
        connect(this, &Widget::sig_save_data, obj, &MyTest::onSaveDatas);
     
        emit sig_save_data("123"); // 发射写信号
        QThread::msleep(1000);     // 测试使用,暂停一会儿
        //obj->onSaveDatas("123");   // 调用写入
    }
     
    Widget::~Widget()
    {
        delete ui;
    }
     

 
二、_End

测试环境

Qt Creator 5.12.8

————————————————
版权声明:本文为CSDN博主「「已注销」」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Lvvou1024/article/details/122820482

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值