QT信号槽的跨线程连接

来源:互联网 发布:如何建立阿里云服务器 编辑:程序博客网 时间:2024/05/22 03:09

QT中的线程可以通过继承QThread类,重写run() 函数,run() 函数即新线程的入(通过start() 函数启动新线程);我我们实现的这个QThread的派生类,只不过是用来管理线程的。run()函数返回,新线程结束,可以在调用 .exec() 函数,在新线程中也开启时间循环。

继承自QObject的对象都会有一个线程依附性,QObject 对象的线程依附性即是创建QObeject对象的线程,可以用 .thread() 函数获得,在QThread对象 的run() 函数中所创建的对象的依附于该QThread 对象,也就是需要通过该QThread 对象来管理。

在QT5中,信号可以连接到一切可以调用的对象上,包括普通函数,成员函数,函数对象,lambda表达式;总的来说,信号与槽的连接有两种方式:1、直接连接 2、队列连接;默认的自动连接下,如果发射信号的线程(而不是发送者所在的线程)与接受者所驻足的线程相同,则是队列连接;如果发送信号的线程与接收者所驻足的不在一个线程,则是队列连接。直接连接下,槽函数在发送信号的线程中立即执行;队列连接情况下,槽函数在接收者所在的线程时间循环处理到时,才执行。

qDebug() << QThread::currentThreadId() << "mainThread";connect(portThread1,&SerialThread::openSuccessSig,[this]            {                qDebug() << QThread::currentThreadId() << "subThread";                this->openFlag1 = true;                this->ui->pushButton_10->setText("关闭");                this->ui->lineEdit_5->setDisabled(true);                connect(this, SIGNAL(writeSig1(QByteArray)),                        portThread1, SIGNAL(myWrite(QByteArray)));               //发送数据 并在发送完毕之后发送完毕信号                connect(portThread1, SIGNAL(transFinWSig()), this, SLOT(finWSlots1()));         //关闭串口  并在关闭之后发回已经关闭的确认信号                connect(this, SIGNAL(toCloseCom1()),                        portThread1, SIGNAL(toCloseCom()));                connect(portThread1, SIGNAL(finCloseCom()),this, SLOT(closedCom1()));                connect(portThread1, SIGNAL(transCode(QString)), this, SLOT(getReadDate1(QString)));            });
这里SerialThread 用来管理子线程,信号currentThreadId() 从子线程中发送过来;构建运行,发生ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 15bb2fd0. Receiver 'lineEdit_5' (of type 'QLineEdit') was created in thread 13fd3478"

的错误,说是lineEdit_5所在的线程与lambda 表达式函数体中所在的线程不同;于是在代码中加入三个qDebug() 语句,打印当前的线程id, 结果发现,lambda 函数体中的线程id 与 SerialThread的run() 函数中输出的线程id() 相同,也就是说,对于lambda 表达式,其执行的线程为信号发送的线程。

解决的办法:想办法使信号从主线程发送过来即可,在SerialThread的run() 函数中, 发送openSuccessSig() 信号的地方改为发送一个新的信号openSuccess() , 新的信号跟新创建一个槽函数openSuccessSlot()连接,在槽函数中发送openSuccessSig()即可,由于槽函数在主线程中执行,所以最终openSuccessSig() 信号会在主线程中发送。

QCoreApplication::postEvent和QCoreApplication::sendEvent

postEvent: 可以给别的线程发送事件,事件会在目的对象所属的线程中运行。这是一个异步接口。sendEvent: 仅用于同一个线程之间发送事件,目的对象所属的线程必须与当前线程一样。这是一个同步接口。假如发送给属于另一个线程的对象,会报错:ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread.

QT中线程的使用还可以通过 .moveToThread() 函数改变一个线程的依附性;于是可以直接创建一个QThread 对象Thread,将一个QObeject对象obj.moveToThread(&Thread),当中,这样,可以使obj的槽函数在次线程中执行;而且此时次线程中仍然有事件循环,可以调用 Thread.quit() 停止事件循环,然后Thread.wait()函数等待结束。需要注意的是,子对象和父对象的线程依附性必须相同,否则会出错。

另外记录一点:用VS编译器,创建窗口对象时,必须的使用小写"com1" ,使用GCC编译器的QT,发现使用小写串口号无法打开串口号10以上,改为大写“COM10”可以解决。


0 0
原创粉丝点击