QLineEdit setText函数导致程序crash的问题解决

很早在程序代码中有个bug,不明原因的崩溃,分析是程序中的指针引起的,查找了很长的时间,没找到,问题依旧。基于此问题出现的频率很低,就此搁浅。 今天偶然在仿真程序是复现了此问题,还定位了调用堆栈,经过一番努力终于解决此大bug。
程序崩的堆栈调用图
问题:
我的问题与这个基本描述基本相同,参考链接如下:
Fast changing QLineEdit crashing the application
https://stackoverflow.com/questions/3571046/fast-changing-qlineedit-crashing-the-application
原因是:
It looks to me like you call setText() from the non-UI thread. That won’t work, QWidgets are not thread-safe
在非GUI线程中调用QWidget方法(非线程安全),程序崩溃。
--------------------------------------------------恍然大悟啊-----------------------------
Qt assistant Threads and QObjects 文中说到:
Although QObject is reentrant, the GUI classes, notably QWidget and all its subclasses, are not reentrant. They can only be used from the main thread. As noted earlier, QCoreApplication::exec() must also be called from that thread.
In practice, the impossibility of using GUI classes in other threads than the main thread can easily be worked around by putting time-consuming operations in a separate worker thread and displaying the results on screen in the main thread when the worker thread is finished. This is the approach used for implementing the Mandelbrot and the Blocking Fortune Client example

原来不能在非GUi线程中调用QWidgets 的方法,于是寻找解决方法,这个大牛给出了解决方案:
If you are calling setText from other than main thread (UI-thread), you just need to move that operation to the main thread. Add a slot function to your mainwindow (where your labels are) and send a signal *with acceleration values as parameters * from your other thread.
也就是说:在非GUI线程中发送信号,在Gui线程中调用QWidget方法即可。
后来检索到了这篇文章,文中使用了QThread实现非GUI线程与GUI线程的通信方法。
在QT中如何实现Thread与GUI的主线程连通
好了,原来使用connect函数,信号和槽的这种机制来解决问题的。那么就来看看这个函数如何实现跨线程通信。
QObject::connect(
const QObject * sender, //发送者
const char * signal, //信号
const QObject * receiver, //接受者
const char * method, //槽函数
Qt::ConnectionType type = Qt::AutoConnection)

这个函数平时都这么用的
connect(this,SIGNAL(upDateTipsStr(const QString &)), m_plabelTips, SLOT(setText(const QString &)));

写成伪代码就是:
if(emit upDateTipsStr(const QString &) )
m_plabelTips->setText();

前四个参数都好理解,第五个参数缺省了。咱们重点看看第五个参数的含义:
Qt::AutoConnection 0 (Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.
默认值,当发送者与接收者处于同一线程中时,使用 Qt::DirectConnection,否则使用Qt::QueuedConnection。

Qt::DirectConnection 1 The slot is invoked immediately when the signal is emitted. The slot is executed in the signalling thread.
槽函数在信号发送的线程中立刻执行

Qt::QueuedConnection 2 The slot is invoked when control returns to the event loop of the receiver’s thread. The slot is executed in the receiver’s thread.
当接收线程接管程序后,槽函数在信号接受的线程中执行

Qt::BlockingQueuedConnection 3 Same as Qt::QueuedConnection, except that the signalling thread blocks until the slot returns. This connection must not be used if the receiver lives in the signalling thread, or else the application will deadlock.
与Qt::QueuedConnection差不多,除了发信号的线程将阻塞直到槽函数执行完毕后,才解除阻塞。注意:当发送信号与槽处于同一线程中时,将出现死锁。

Qt::UniqueConnection 0x80 This is a flag that can be combined with any one of the above connection types, using a bitwise OR. When Qt::UniqueConnection is set, QObject::connect() will fail if the connection already exists (i.e. if the same signal is already connected to the same slot for the same pair of objects). This flag was introduced in Qt 4.6.
可与上述的flag进行OR操作,当相同的信号连接了形同的槽函数时,该connect将返回false。
总结:也就是说当跨线程使用connect时,默认使用的类型Qt::QueuedConnection。
至此,此问题算是告一段落。
如果您还有什么好的解决方法欢迎留言。


2018年12月13日 19:46:03
南京

追求进步
永不止步

猜你喜欢

转载自blog.csdn.net/u013804856/article/details/84994068