Qt跨线程调用错误解析及解决办法

摘要:
在_connect()函数中调用start()函数启动线程,自动调用重载的run()函数。}该错误是跨线程调用引起的。无论槽函数所属对象在哪个线程,槽函数总在发送者所在线程执行。3)队列连接,当控制权回到接受者所在线程的事件循环时,槽函数被调用。对于一些耗时的操作,如果放在主线程中,就会出现界面无法响应的问题。

错误提示:Error: Cannot create children for a parent that is in a different thread.

错误案例分析

新建SerialLink子线程,继承QThread,并重写它的run(),调用 start()函数时自动调用重载的run()函数。在主线程中创建SerialLink类的对象。

串口_port在SerialLink的头文件中定义,在_hardwareConnect()函数中初始化。在_connect()函数中调用start()函数启动线程,自动调用重载的run()函数。

Class SerialLink: public QThread
{ 
……
QSerialPort* _port;
 ……	
}

void SerialLink:: _hardwareConnect( )
{
……
_port = new SerialPort( );
……
}

void SerialLink:: _connect( )
{
……
_hardwareConnect( );
start( );
……
}

void SerialLink:: run( )
{
……
}

该错误是跨线程调用引起的。

原因:_port的初始化是在SerialLink类中,SerialLink子线程是在主线程中创建的子线程,在SerialLink对象本身工作在主线程下,其中定义的所有东西都属于创建SerialLink的线程,即主线程,所以_port应该是属于主线程(父线程)的;只有run()范围内的代码工作在次线程中,所以在SerialLink的run()中调用_port属于跨线程调用,就会出现异常。

解决办法:_portrun函数中初始化,_port就是在同一子线程中创建和调用,不会出现跨线程调用错误。

void SerialLink*run( )
{
_hardwareConnect( );
……
}
void SerialLink*_connect( )
{
……
start( );
……
}
void_hardwareConnect( )
{
……
_port = newSerialPort( );
……
}

总结

Thread对象本身工作在主线程下,即使调用其定义的变量和方法,也是工作在主线程下,只有run()范围内的代码才工作在子线程中。为避免跨线程调用引起异常,一个对象的创建和调用要放在同一线程中。

推荐的工作方式:利用Qt的事件驱动特性,将需要在次线程中处理的业务放在独立的模块(类)中,由主线程创建完该对象后,将其移交给指定的线程,且可以将多个类似的对象移交给同一个线程。

connect连接类型:

1) 自动连接(AutoConnection),默认的连接方式,如果信号与槽,也就是发送者与接受者在同一线程,等同于直接连接;如果发送者与接受者处在不同线程,等同于队列连接。

2) 直接连接(DirectConnection),当信号发射时,槽函数立即直接调用。无论槽函数所属对象在哪个线程,槽函数总在发送者所在线程执行。

3) 队列连接(QueuedConnection),当控制权回到接受者所在线程的事件循环时,槽函数被调用。槽函数在接受者所在线程执行。

在GUI程序中,主线程也叫GUI线程,因为它是唯一被允许执行GUI相关操作的线程。对于一些耗时的操作,如果放在主线程中,就会出现界面无法响应的问题。这种问题的一种解决方式是,把这些耗时操作放到子线程中。

免责声明:文章转载自《Qt跨线程调用错误解析及解决办法》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇记一次 SpringBoot2.x 配置 Fastjson 的坑--修正版Windows杂记——Compact 命令下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Jmeter(十二)

------------------------------------------------------------------- 转载自:北京-宏哥 https://www.cnblogs.com/du-hong/p/13100499.html -----------------------------------------------------...

linux kernel的cmdline參数解析原理分析

利用工作之便,今天研究了kernel下cmdline參数解析过程。记录在此。与大家共享。转载请注明出处。谢谢。 Kernel 版本:3.4.55 Kernel启动时会解析cmdline,然后依据这些參数如console root来进行配置执行。 Cmdline是由bootloader传给kernel。如uboot。将须要传给kernel的參数做成一个...

Handler 机制(一)—— Handler的实现流程

   由于Android采用的是单线程模式,开发者无法在子线程中更新 UI,所以系统给我提供了 Handler 这个类来实现 UI 更新问题。本贴主要说明 Handler 的工作流程。 1. Handler 的作用 在Android为了保障线程安全,规定只能由主线程来更新UI信息。而在实际开发中,会经常遇到多个子线程都去操作UI信息的情况,那么就会导致U...

磁盘IO读写流程图

  对于read系统调用在内核的处理,如上图所述,经过了VFS、具体文件系统,如ext2、页高速缓冲存层、通用块层、IO调度层、设备驱动层、和设备层。其中,VFS主要是用来屏蔽下层具体文件系统操作的差异,对上提供一个统一接口,正是因为有了这个层次,所以可以把设备抽象成文件。具体文件系统,则定义了自己的块大小、操作集合等。引入cache层的目的,是为了提高I...

Java 8 (10) CompletableFuture:组合式异步编程

https://www.cnblogs.com/baidawei/p/9447737.html   随着多核处理器的出现,提升应用程序的处理速度最有效的方式就是可以编写出发挥多核能力的软件,我们已经可以通过切分大型的任务,让每个子任务并行运行,使用线程的方式,分支/合并框架(java 7) 和并行流(java 8)来实现。 现在很多大型的互联网公司都对外...

《Linux 应用编程》—第13章 Linux 多线程编程

目录 1 多线程概述 1.1 什么是线程 1.2 线程与进程的关系 1.3 为什么使用多线程 2 POSIX Threads 概述 3 线程管理 3.1 线程ID 3.2 创建与终止 1. 创建线程 2. 终止线程 3. 线程范例1 3.3 连接与分离 1. 线程分离 2. 线程连接 3. 线程范例2 3.4 线程属性 属性对象...