如何防止QT事件堆栈溢出?

3
我正在制作一个QT应用程序,它根据从套接字接收到的信息更新窗口。这是我处理此事的方式:
  1. 设置定时器以导致应用程序检查套接字

  2. 在接收到新信息(如果有)后,更改在绘制小部件中使用的上下文数据并调用其重新绘制

  3. 自然地,我的绘图代码需要在绘图事件中执行

但是,我遇到了一个问题。该应用程序不稳定,并且会随机崩溃(通常在发送到套接字开始后)。在调试下,堆栈跟踪显示它在QT本身的深处崩溃 - 我根据堆栈猜测,这是另一个绘图事件的分配。
如何防止这种情况发生?也许,如果绘画实际上尚未完成,则不要调用重新绘制?
处理接收新数据的代码; dt.listen()返回更改项目的数量。
void CommandPanel::update()
{
    //printf("Some drawing is done!\n");
    static int udel = 0;
    udel += 1+dt.listen();
    if ( udel > 40)
    {
        this->repaint(); //!!!
        udel = 0;
    }
}

将代码绑定到计时器

//object T that is derived from QWidget is created
QTimer timer;
QObject::connect(&timer, SIGNAL(timeout()), &T, SLOT(update()));
timer.start(1000 / 10);
T.show();

在调试期间,当我到达带有“!!!”注释的行时,我收到了分段错误信号。以下是完整的堆栈跟踪。
线程3(线程0xb75b9b70(LWP 9183)): _#0 0x0012e416 in __kernel_vsyscall() 没有可用的符号表信息。
_#1 0x00e49834中的pthread_cond_timedwait@@GLIBC_2.3.2()来自/lib/i386-linux-gnu/libpthread.so.0 没有可用的符号表信息。
_#2 0x01472f0e在??()中(来自/usr/lib/i386-linux-gnu/libgthread-2.0.so.0) 没有可用的符号表信息。
_#3 0x0114042c在??()中(来自/lib/i386-linux-gnu/libglib-2.0.so.0) 没有可用的符号表信息。
_#4 0x01140f6d中的g_async_queue_timed_pop()来自/lib/i386-linux-gnu/libglib-2.0.so.0 没有可用的符号表信息。
_#5 0x01198980在??()中(来自/lib/i386-linux-gnu/libglib-2.0.so.0) 没有可用的符号表信息。
_#6 0x011962df在??()中(来自/lib/i386-linux-gnu/libglib-2.0.so.0) 没有可用的符号表信息。
_#7 0x00e44e99中的start_thread()来自/lib/i386-linux-gnu/libpthread.so.0 没有可用的符号表信息。
_#8 0x0105573e中的clone()来自/lib/i386-linux-gnu/libc.so.6 没有可用的符号表信息。
线程2(线程0xb7dbab70(LWP 9072)): _#0 0x0012e416 in __kernel_vsyscall() 没有可用的符号表信息。
_#1 0x01046f76中的poll()来自/lib/i386-linux-gnu/libc.so.6 没有可用的符号表信息。
_#2 0x0117d84b中的g_poll()来自/lib/i386-linux-gnu/libglib-2.0.so.0 没有可用的符号表信息。
_#3 0x0116d1af在??()中(来自/lib/i386-linux-gnu/libglib-2.0.so.0) 没有可用的符号表信息。
_#4 0x0116d92b中的g_main_loop_run()来自/lib/i386-linux-gnu/libglib-2.0.so.0 没有可用的符号表信息。

_#5 0x0166b304 在 /usr/lib/i386-linux-gnu/libgio-2.0.so.0 中,没有可用的符号表信息。 _#6 0x011962df 在 /lib/i386-linux-gnu/libglib-2.0.so.0 中,没有可用的符号表信息。

_#7 0x00e44e99 在 /lib/i386-linux-gnu/libpthread.so.0 中的 start_thread() 函数中,没有可用的符号表信息。

_#8 0x0105573e 在 /lib/i386-linux-gnu/libc.so.6 中的 clone() 函数中,没有可用的符号表信息。

线程 1 (线程 0xb7fe4710 (LWP 8938)): _#0 0x00d183f8 的 QMetaObject::activate(QObject*, QMetaObject const*, int, void**) () 来自 /usr/lib/libQtCore.so.4 没有可用的符号表信息。

_#1 0x00d652f7 的 QTimer::timeout() 函数来自 /usr/lib/libQtCore.so.4,没有可用的符号表信息。

_#2 0x00d1e3ee 的 QTimer::timerEvent(QTimerEvent*) 函数来自 /usr/lib/libQtCore.so.4,没有可用的符号表信息。

_#3 0x00d17214 的 QObject::event(QEvent*) 函数来自 /usr/lib/libQtCore.so.4,没有可用的符号表信息。

_#4 0x0025cd24 在 /usr/lib/libQtGui.so.4 中的 QApplicationPrivate::notify_helper(QObject*, QEvent*) 函数中,没有可用的符号表信息。

_#5 0x002618ce 的 QApplication::notify(QObject*, QEvent*) 函数来自 /usr/lib/libQtGui.so.4,没有可用的符号表信息。

_#6 0x00d020bb 的 QCoreApplication::notifyInternal(QObject*, QEvent*) 函数来自 /usr/lib/libQtCore.so.4,没有可用的符号表信息。

_#7 0x00d321e4,没有可用的符号表信息,来自 /usr/lib/libQtCore.so.4。

_#8 0x00d2ee27,没有可用的符号表信息,来自 /usr/lib/libQtCore.so.4。

_#9 0x0116caa8 在 /lib/i386-linux-gnu/libglib-2.0.so.0 中的 g_main_context_dispatch() 函数中,没有可用的符号表信息。

_#10 0x0116d270,没有可用的符号表信息,来自 /lib/i386-linux-gnu/libglib-2.0.so.0。

_#11 0x0116d524 在 /lib/i386-linux-gnu/libglib-2.0.so.0 中的 g_main_context_iteration() 函数中,没有可用的符号表信息。

_#12 0x00d2f53c in QEventDispatcherGlib::processEvents(QFlags) () from /usr/lib/libQtCore.so.4 没有可用的符号表信息。

_#13 0x00310775 in ?? () from /usr/lib/libQtGui.so.4 没有可用的符号表信息。

_#14 0x00d01289 in QEventLoop::processEvents(QFlags) () from /usr/lib/libQtCore.so.4 没有可用的符号表信息。

_#15 0x00d01522 in QEventLoop::exec(QFlags) () from /usr/lib/libQtCore.so.4 没有可用的符号表信息。

_#16 0x00d05ecc in QCoreApplication::exec() () from /usr/lib/libQtCore.so.4 没有可用的符号表信息。

_#17 0x0025a8e7 in QApplication::exec() () from /usr/lib/libQtGui.so.4 没有可用的符号表信息。

_#18 0x0804ac19 in main (argc=1, argv=0xbffff8a4) at ../wargui/main.cpp:40

该段文本是一组程序错误信息,指出了发生错误的函数和源文件路径。这些信息通常由计算机编译器生成,并用于帮助开发人员调试代码。如果您遇到类似的问题,请联系您的开发团队或技术支持,以获取更多帮助和支持。
    app = <incomplete type>
    timer = <incomplete type>
    T = {<QLabel> = {<No data fields>}, view = 0x10e33c0, dt = {qflag = 0, channelSockets = {0x8566108 "/tmp/channel1", 0x8567788 "/tmp/channel2", 0x8565298 "/tmp/channel3", 0x8565330 "/tmp/channel4", 0x8567db8 "/tmp/channel5", 0x8567e00 "/tmp/channel6", 0x8567108 "/tmp/channel7"}, mesSources = {0x8567e78, 0x85653a0, 0x85652b0, 0x8565348, 0x8567dd0, 0x85670d8, 0x8567120}, cossock = 33, chansocks = {26, 27, 28, 29, 30, 31, 32}, logLength = {0, 0, 0, 0, 0, 0, 0, 1, 1}, logs = {0x8568620, 0x8568788, 0x85688f0, 0x8568a58, 0x8568bc0, 0x8568d28, 0x8568e90, 0x8568ff8, 0x8569160}, targets = 0x85651e0}}
    pm = <incomplete type>
    r = -1073743880

我还需要补充以下内容。 如果 Qt 应用程序在消息到达套接字之前启动,则它可以正常工作而不会崩溃。否则,当消息已经开始发送,然后启动 Qt 应用程序时,一旦调用 update(),它就会崩溃。

4
也许有人会有不同意见,但我认为如果没有展示你正在做什么的最小代码,或者更详细的关于错误/堆栈跟踪的信息,这个问题可能会太难回答了。请提供这些信息以帮助我们更好地理解和解决问题。 - Bart
“通过调用它的重绘方法”是什么意思?QWidget 上没有重绘方法。如果您正在使用 repaint,请仔细查看该函数文档中的警告。 - Mat
2
a) 使用QSocketNotifier b) 调用update()而不是repaint()(并重命名/删除您自己的update()) - Frank Osterfeld
你能详细说明一下你的 b) 吗? - Srv19
2
QT文档中提到:警告:如果您在一个可能从paintEvent()调用的函数中调用repaint(),则可能会出现无限递归。update()函数永远不会导致递归。(http://doc.trolltech.com/4.7/qwidget.html#repaint) - gnud
2
覆盖update()方法而不调用原始方法似乎是一件冒险的事情。在您的update函数中,不要调用repaint(),而是直接调用原始的update()方法。 - gnud
2个回答

2
当您从网络接收到消息时,请将传入数据与当前数据进行比较。如果有变化,则更新数据并发出“更新GUI”事件。如果仍然太快,则每秒最多只发出X个更新事件。
最好的做法是让您的网络代码不知道GUI的任何信息(即不要调用“repaint”)。而是发出“更新”事件,GUI可以根据需要处理它。如果更改GUI,则您的网络代码不会更改。

1

我第一次重写update()方法时也遇到了这种问题。

Gnud是正确的,直接调用原始的update()应该可以解决你的问题。如果在绘制事件发生时需要进行某些操作/绘制/更新/绘画,则重新实现paintEvent(QPaintEvent*)

此外,为了触发您的绘图事件,您可以将一个槽连接到readyRead() QSocket信号。在此槽中,您可以评估bytesAvailable(),直到达到足够的数据量。然后调用update()。您还应该创建/重置一个一次性定时器,以防刚刚接收到的数据是最后一批数据,而且永远不会达到“足够”的数量!


好的,遵循建议,程序在某种程度上开始工作了。值得庆幸的是,它没有实际应用。 - Srv19

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接