Как предотвратить переполнение стека событий QT? - PullRequest
3 голосов
/ 18 мая 2011

Я делаю приложение 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 в __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 в __kernel_vsyscall () Информация о таблице символов недоступна.

_ # 1 0x01046f76 в опросе () из /lib/i386-linux-gnu/libc.so.6 Информация о таблице символов недоступна.

_ # 2 0x0117d84b в g_poll () из /lib/i386-linux-gnu/libglib-2.0.so.0 Информация о таблице символов недоступна.

_ # 3 0x0116d1af in ?? () из /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 in ?? () из /usr/lib/i386-linux-gnu/libgio-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 Информация о таблице символов недоступна.

Тема 1 (Тема 0xb7fe4710 (LWP 8938)): _ # 0 0x00d183f8 в QMetaObject :: activ (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 в QApplicationPrivate :: notify_helper (QObject *, QEvent *) () из /usr/lib/libQtGui.so.4 Информация о таблице символов недоступна.

_ # 5 0x002618ce в QApplication :: notify (QObject *, QEvent *) () из /usr/lib/libQtGui.so.4 Информация о таблице символов недоступна.

_ # 6 0x00d020bb в QCoreApplication :: notifyInternal (QObject *, QEvent *) () из /usr/lib/libQtCore.so.4 Информация о таблице символов недоступна.

_ # 7 0x00d321e4 in ?? () из /usr/lib/libQtCore.so.4 Информация о таблице символов недоступна.

_ # 8 0x00d2ee27 в ?? () из /usr/lib/libQtCore.so.4 Информация о таблице символов недоступна.

_ # 9 0x0116caa8 в g_main_context_dispatch () из /lib/i386-linux-gnu/libglib-2.0.so.0 Информация о таблице символов недоступна.

_ # 10 0x0116d270 in ?? () из /lib/i386-linux-gnu/libglib-2.0.so.0 Информация о таблице символов недоступна.

_ # 11 0x0116d524 в g_main_context_iteration () из /lib/i386-linux-gnu/libglib-2.0.so.0 Информация о таблице символов недоступна.

_ # 12 0x00d2f53c в QEventDispatcherGlib :: processEvents (QFlags) () из /usr/lib/libQtCore.so.4 Информация о таблице символов недоступна.

_ # 13 0x00310775 в ?? () из /usr/lib/libQtGui.so.4 Информация о таблице символов недоступна.

_ # 14 0x00d01289 в QEventLoop :: processEvents (QFlags) () из /usr/lib/libQtCore.so.4 Информация о таблице символов недоступна.

_ # 15 0x00d01522 в QEventLoop :: exec (QFlags) () из /usr/lib/libQtCore.so.4 Информация о таблице символов недоступна.

_ # 16 0x00d05ecc в QCoreApplication :: exec () () из /usr/lib/libQtCore.so.4 Информация о таблице символов недоступна.

_ # 17 0x0025a8e7 в QApplication :: exec () () из /usr/lib/libQtGui.so.4 Информация о таблице символов недоступна.

_ # 18 0x0804ac19 в основном (argc = 1, argv = 0xbffff8a4) в ../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 ().

Ответы [ 2 ]

1 голос
/ 19 мая 2011

Я столкнулся с такого рода проблемами в первый раз, когда переопределил метод update ().

Gnud правильно называет оригинал update(), который должен решить вашу проблему, если вам нужно что-то сделать / нарисовать / обновить / нарисовать, когда происходит событие рисования, повторно внедрите paintEvent(QPaintEvent*).

В дополнение к этому, чтобы вызвать событие рисования, вы можете подключить слот к сигналу readyRead() QSocket. В этом слоте вы можете оценивать bytesAvailable(), пока не будет достигнут приличный объем данных. Тогда вы звоните update(). Вы также должны создать / сбросить таймер однократной проверки на тот случай, если только что полученные вами данные были последними, и «приличная» сумма никогда не будет достигнута!

1 голос
/ 18 мая 2011

При получении сообщения из сети сравните входящие данные с текущими данными. Если он изменится, обновите данные и отправьте событие update the gui. Если это все еще слишком быстро, генерируйте только события обновления с максимальной скоростью X в секунду.

Это хорошая практика, чтобы ваш сетевой код ничего не знал о графическом интерфейсе (т. Е. Не называть перерисовкой). Вместо этого сгенерируйте событие «update», и графический интерфейс может обработать его по своему усмотрению. Если вы измените свой графический интерфейс, то сетевой код не изменится.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...