关于QT中信号与槽的参数传递,作用域的问题,崩溃

提前记录一个现象:在QTcreator中,Debug信息出现C:\Program Files (x86)\sogoupinyin\Components\这个莫名其妙的信息的时候,百分之百是因为程序里引用了某个野指针 

很奇怪为什么是搜狗拼音...如果没安装搜狗拼音输入法,这里会出现什么,微软输入法吗...?

近期在一个项目中用了多线程技术。结构其实很简单:

主线程A主要负责过程控制和界面维护。每个传感器又一个子线程B负责维护,数据由子线程进行采集和处理,完成处理后,将数据结果和图片通过信号传递回主线程,并在UI上显示。

最开始,是通过回调函数的方式工作。主线程初始化子线程的时候,将界面上控件C的指针直接传递给子线程,由子线程调用控件的方法进行显示。这个方法在我的机器上一直工作正常。但是将代码带到现场工控机上工作时,只要一显示就有可能发生崩溃,并且随着使用时间增加,崩溃概率越来越大。

在排除了硬件问题后,怀疑是因为线程之间直接调用指针的问题引起的。

后来索性花了一个晚上,将所有的函数都改为通过信号和槽传递消息。这种方法被证明比第一种更靠谱,在编程主机和现场工控机都能正常工作。

但是在后来的工作中,程序内容越来越多,又开始出现崩溃问题,出现的提示依旧是搜狗拼音输入法。再次熬夜debug,发现崩溃只发生在一个子线程B更新控件C上的图片时出现。

扫描二维码关注公众号,回复: 12723828 查看本文章

吊鬼的是,明明C控件已经收到了这种图片,并且debug显示图片的大小都是正正常的!但是后续将图片转化为qpixmap进行显示,就会提示搜狗拼音!

于是晚上又挠掉了一地头发,发现无论是通过最早的直接调用,或者通过QT的信号机制(connect的时候已经加上了 Qt::QueuedConnection标记位了),程序传递的参数都是一个跟发送(调用)者有关的一片内存。

怀疑是当这个参数被调用的时候,如果发送(调用)者由于某种原因被释放掉了,那么这个内存就变成了一个莫名的地方,调用它的指针就会变成野指针!

于是来看debug结果

[B的成员]处理结束Time used: 2117 ms

[B的成员]生成Mat图片 数据指针= 0x21e88aff080

[B]callbackSetImage  this thread= 0x6544  生成并发送qimage图片  数据指针= 0x21efeb87ad0 

[C]get image, this thread= 0x447c , image size= QSize(3200, 5074) sn= "" sender= LJXCapture(0x21ef603a140) image pointer= 0x21efeb87ad0

C:\Program Files (x86)\sogoupinyin\Components\

05:38:02: 程序异常结束。

上面可见,B中通过CV::MAT生成了一个QIMAGE,并且通过信号发送刚出去。B和C不在一个线程,但是C收到的QIMAGE的地址和B发送的是一样的。也就是说,并没有通过某种机制,来产生一个新的QIMAGE复制体来传递给C,这个和我原来预想的情况并不一样!

恰恰在B发送这个信号的函数中,发送图像的信号是函数最后发出的。发送的信号中,这个图像也是一个局部变量!刚刚发送出去,控件C接收到这个指针的时候,这个地址还没有被释放掉。但是当图片要进行转换显示的时候,好死不死的B的函数返回了,这个局部变量变成了孤魂野鬼一样的野指针...

妈的,说好的线程安全呢,说好的消息机制呢

手动在B线程发送信号的语句以后,加上了Sleep(1000)给这个函数强行续命,结果果然就不崩了!但是Sleep还是会影响性能,不能作为长久的解决方案...

最终的解决方案,在B初始化的时候,申明一个全局变量,用这个全局变量作为发送数据的载体。这时即使删掉Sleep也不会在出现前面的崩溃问题。

猜你喜欢

转载自blog.csdn.net/laoponline/article/details/114472545