Problem with QTimer --> get message "Object::startTimer: Timers cannot be started from another thread"
-
Hi,
In my program, I have a MIDIControllerGenericDialogMOD1 class where I define a static variable to hold a pointer a BlownUpParamDisplay class (derived from) QDialog.
I declare the pointer to BlownUpParamDisplay to be static since I only need one instance of that classstatic BlownUpParamDisplay *m_dlgBlownUpParamDisplay;
and also declare a QTimer that will allow me to hide the m_dlgBlownUpParamDisplay window after 1.5 sec :
QTimer m_timerDlgBlownUpParamDisplay;
The link is made with :
connect( &m_timerDlgBlownUpParamDisplay, SIGNAL(timeout()), this, SLOT(closeDlgBlownUpParamDisplay()) );
and there is a start and a stop disaplay function
void MIDIControllerGenericDialogMOD1::closeDlgBlownUpParamDisplay() { m_dlgBlownUpParamDisplay->hide(); this->raise(); } void MIDIControllerGenericDialogMOD1::startDlgBlownUpParamDisplayTimer() { m_timerDlgBlownUpParamDisplay.setSingleShot(true); m_timerDlgBlownUpParamDisplay.start(1500); }
For the m_dlgBlownUpParamDisplay window :
it is defined (in .h file) by :static BlownUpParamDisplay *m_dlgBlownUpParamDisplay;
initialized (in .cpp file) by :
BlownUpParamDisplay *MIDIControllerGenericDialogMOD1::m_dlgBlownUpParamDisplay = NULL;
and created in the creator function of the by :
if( m_dlgBlownUpParamDisplay == NULL) m_dlgBlownUpParamDisplay = new BlownUpParamDisplay;
just before the Signal/Slot connection is made :
connect( &m_timerDlgBlownUpParamDisplay, SIGNAL(timeout()), this, SLOT(closeDlgBlownUpParamDisplay()) );
The PROBLEMS I get with that code are :
-
When the startDlgBlownUpParamDisplayTimer is called in the program, I get the following message in the application output
"Object::startTimer: Timers cannot be started from another thread" -
When the closeDlgBlownUpParamDisplay is called in the program, I get the following message in the application output
"Object::killTimer: Timers cannot be stoped from another thread" -
The m_dlgBlownUpParamDisplay window is displayed (and updated with new info) but never closes (apart from manually). It's a shame because all that code is to make the windows automatically disappear after 1.5 sec.
The program does not used QThread. only the RTMIDI lib used in the program has a C pthread for input MIDI messages. This display of the m_dlgBlownUpParamDisplay window happens after the MIDI callback function is used.
I had this code working before but I was going through the application message queue after receiving a MIDI message, so I guess I was actually changing thread. I would like to avoid that because I don't want the message to go through a queue where there could be queued up after other messages and I need the MIDI message to be processed as soon as they are received. So I you have an idea on how to make that code work without going through the main application message queue please let me know.
Thanks in advanCe for the help.
-
-
U must be creating qtimer in one thread and trying to start the timer in another thread. Just check ownership of qtimer object
-
Yes that is likely what is going on. --> I'll check ownership tomorrow .
In the meantime I tried sending Start/stop event for the display to solve the problem. That way the MIDI message get processed immediatly and the refresh of the BlownUp screen get done potentially latter through the event queue :
void MIDIControllerGenericDialogMOD1::customEvent ( QEvent *event ) { //QString MIDI_Message = QString("Message Received" ); //ui.logMIDI->append(MIDI_Message); //qDebug() << "customEvent:" << event->type(); if( event->type() == BlownUpStartEventType) { startDlgBlownUpParamDisplayTimer(); } if( event->type() == BlownUpStopEventType) { closeDlgBlownUpParamDisplay(); } }
the start event is send with :
ev = new BlownUpStartEvent( ); QApplication::postEvent(this, ev);
and the stop event is triggered by the timeout() signal
connect( &m_timerDlgBlownUpParamDisplay, SIGNAL(timeout()), this, SLOT(closeDlgBlownUpParamDisplay()) );
On Qt5.8 on DEBIAN8 (with gnome) the program works fine now. But when I compile an run it in my WIN10 virtualBox with Qt5.7 the program just crashes when I activate the display of the BlownUp window. Weird !
-
After checking, I also get an error message in the Application Output in WIN10/QT5.7 environnement:
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 1bde7af0. Receiver 'verticalSlider_1' (of type 'QSliderMod1') was created in thread 1858c390", file kernel\qcoreapplication.cpp, line 541
which does not appear in DEBIAN8/QT5.8 environment. --> Maybe it is a bug in Qt version 5.7 that was fixed 5.8 ?
-
After checking, I also get an error message in the Application Output in WIN10/QT5.7 environnement:
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 1bde7af0. Receiver 'verticalSlider_1' (of type 'QSliderMod1') was created in thread 1858c390", file kernel\qcoreapplication.cpp, line 541
which does not appear in DEBIAN8/QT5.8 environment. --> Maybe it is a bug in Qt version 5.7 that was fixed 5.8 ?
Run your program through the debugger, break at the assertion, inspect the stack trace. Also the message is pretty descriptive, you're sending events from a thread different from main (or at least I assume it's the main thread that creates the slider).
Maybe it is a bug in Qt version 5.7 that was fixed 5.8 ?
I really doubt it. Check your code.
-
Thanks for your help kshegunov (and thanks you to dheerendra for the first answer)
Here is the call stack after breaking on (before) the Assertion :
1 QCoreApplicationPrivate::checkReceiverThread qcoreapplication.cpp 533 0xbb52f6 2 QApplication::notify qapplication.cpp 3021 0x5a8a44 3 QCoreApplication::notifyInternal2 qcoreapplication.cpp 988 0xbb6187 4 QCoreApplication::sendEvent qcoreapplication.h 231 0xe425b3 5 QWidgetPrivate::propagatePaletteChange qwidget.cpp 2016 0x568e2c 6 QWidgetPrivate::setPalette_helper qwidget.cpp 4654 0x56e6e6 7 QWidget::setPalette qwidget.cpp 4584 0x56e364 8 MIDIControllerGenericDialogMOD1::colorSlider midicontrollergenericdialogmod1.cpp 466 0x42a07b 9 MIDIControllerGenericDialogMOD1::setSliderValue midicontrollergenericdialogmod1.cpp 404 0x429c2e 10 MIDIControllerGenericDialogMOD1::setValue midicontrollergenericdialogmod1.cpp 628 0x42a932 11 MidyAX::processSYSEXReceivedFromAXEFX midyax.cpp 2089 0x40d087 12 midiCallback_AXEFX midyax.cpp 667 0x406f43 13 midiInputCallback RtMidi.cpp 2067 0x4137f6 14 WINMMBASE!DriverCallback 0x14db27 15 midMessage 0x5d5ff990 16 midMessage 0x5d5fff6c 17 midMessage 0x5d5ffe0d 18 midMessage 0x5d5ffb3c 19 KERNEL32!BaseThreadInitThunk 0x76ff8e94 20 ntdll!RtlDestroyQueryDebugBuffer 0x779b9bc3 21 ntdll!RtlDestroyQueryDebugBuffer 0x779b9b92 22 ??
at level 13 is the function that receive the MIDI message from Win10. My code stops at level 8 to color the slider. All this is going on in thread 5 and thread 1 (of 8) seems to be the main thread :
1 QMetaObject::inherits qmetaobject.cpp 339 0xbade85 2 QMetaObject::cast qmetaobject.cpp 366 0xbadeda 3 QMetaObject::cast qmetaobject.cpp 355 0xbadea9 4 qobject_cast<QAbstractButton *> qobject.h 516 0xd8c46a 5 QWindowsXPStyle::polish qwindowsxpstyle.cpp 1317 0x72f6e0 6 QWindowsVistaStyle::polish qwindowsvistastyle.cpp 2303 0x74ce27 7 QWidget::event qwidget.cpp 8876 0x579b61 8 QAbstractSlider::event qabstractslider.cpp 958 0x504239 9 QSlider::event qslider.cpp 359 0x4a39c8 10 QApplicationPrivate::notify_helper qapplication.cpp 3799 0x5ab73e 11 QApplication::notify qapplication.cpp 3762 0x5ab584 12 QCoreApplication::notifyInternal2 qcoreapplication.cpp 988 0xbb6187 13 QCoreApplication::sendEvent qcoreapplication.h 231 0xe425b3 14 QWidget::ensurePolished qwidget.cpp 10018 0x57b2f7 15 QWidget::ensurePolished qwidget.cpp 10027 0x57b36f 16 QWidget::ensurePolished qwidget.cpp 10027 0x57b36f 17 QWidget::ensurePolished qwidget.cpp 10027 0x57b36f 18 QWidget::event qwidget.cpp 8872 0x579b3b 19 QMainWindow::event qmainwindow.cpp 1543 0x4c8b46 20 QApplicationPrivate::notify_helper qapplication.cpp 3799 0x5ab73e 21 QApplication::notify qapplication.cpp 3762 0x5ab584 22 QCoreApplication::notifyInternal2 qcoreapplication.cpp 988 0xbb6187 23 QCoreApplication::sendEvent qcoreapplication.h 231 0xe425b3 24 QCoreApplicationPrivate::sendPostedEvents qcoreapplication.cpp 1649 0xbb73d3 25 QEventDispatcherWin32::sendPostedEvents qeventdispatcher_win.cpp 1294 0xb774c6 26 QWindowsGuiEventDispatcher::sendPostedEvents qwindowsguieventdispatcher.cpp 81 0x7a1677 27 qt_internal_proc(HWND__ *, unsigned int, unsigned int, long) *16 qeventdispatcher_win.cpp 443 0xb74782 28 USER32!RecordShutdownReason 0x75418233 29 USER32!DispatchMessageW 0x753ee638 30 USER32!DispatchMessageW 0x753ee103 31 USER32!DispatchMessageW 0x753edf50 32 QEventDispatcherWin32::processEvents qeventdispatcher_win.cpp 844 0xb75d0e 33 QWindowsGuiEventDispatcher::processEvents qwindowsguieventdispatcher.cpp 74 0x7a1645 34 QCoreApplication::processEvents qcoreapplication.cpp 1206 0xbb6667 35 delay midyax.cpp 1997 0x40ca37 36 MidyAX::getMidiMappingParamValues midyax.cpp 1505 0x409e9d 37 MidyAX::init midyax.cpp 316 0x404fd0 38 MidyAX::MidyAX midyax.cpp 110 0x40294e 39 qMain main.cpp 15 0x4016b5 40 WinMain *16 qtmain_win.cpp 123 0x43c290 41 main 0x1148ecd
The color slider event is not in the main thread and the slider has been created in the main thread. But the same code has been working before on Qt5.7/WIN10 and is working in DEBIAN8/Qt5.8, isn't that a bit abnormal ? or not.
I tried to get the call stack in the DEBIAN8/Qt5.8, but I can't get the program to breack --> must be a set-up issue were the debugger is not talled to use the debug lib or some other config problem. Not sure what to check in Qt Creator.
-
Thanks for your help kshegunov (and thanks you to dheerendra for the first answer)
Here is the call stack after breaking on (before) the Assertion :
1 QCoreApplicationPrivate::checkReceiverThread qcoreapplication.cpp 533 0xbb52f6 2 QApplication::notify qapplication.cpp 3021 0x5a8a44 3 QCoreApplication::notifyInternal2 qcoreapplication.cpp 988 0xbb6187 4 QCoreApplication::sendEvent qcoreapplication.h 231 0xe425b3 5 QWidgetPrivate::propagatePaletteChange qwidget.cpp 2016 0x568e2c 6 QWidgetPrivate::setPalette_helper qwidget.cpp 4654 0x56e6e6 7 QWidget::setPalette qwidget.cpp 4584 0x56e364 8 MIDIControllerGenericDialogMOD1::colorSlider midicontrollergenericdialogmod1.cpp 466 0x42a07b 9 MIDIControllerGenericDialogMOD1::setSliderValue midicontrollergenericdialogmod1.cpp 404 0x429c2e 10 MIDIControllerGenericDialogMOD1::setValue midicontrollergenericdialogmod1.cpp 628 0x42a932 11 MidyAX::processSYSEXReceivedFromAXEFX midyax.cpp 2089 0x40d087 12 midiCallback_AXEFX midyax.cpp 667 0x406f43 13 midiInputCallback RtMidi.cpp 2067 0x4137f6 14 WINMMBASE!DriverCallback 0x14db27 15 midMessage 0x5d5ff990 16 midMessage 0x5d5fff6c 17 midMessage 0x5d5ffe0d 18 midMessage 0x5d5ffb3c 19 KERNEL32!BaseThreadInitThunk 0x76ff8e94 20 ntdll!RtlDestroyQueryDebugBuffer 0x779b9bc3 21 ntdll!RtlDestroyQueryDebugBuffer 0x779b9b92 22 ??
at level 13 is the function that receive the MIDI message from Win10. My code stops at level 8 to color the slider. All this is going on in thread 5 and thread 1 (of 8) seems to be the main thread :
1 QMetaObject::inherits qmetaobject.cpp 339 0xbade85 2 QMetaObject::cast qmetaobject.cpp 366 0xbadeda 3 QMetaObject::cast qmetaobject.cpp 355 0xbadea9 4 qobject_cast<QAbstractButton *> qobject.h 516 0xd8c46a 5 QWindowsXPStyle::polish qwindowsxpstyle.cpp 1317 0x72f6e0 6 QWindowsVistaStyle::polish qwindowsvistastyle.cpp 2303 0x74ce27 7 QWidget::event qwidget.cpp 8876 0x579b61 8 QAbstractSlider::event qabstractslider.cpp 958 0x504239 9 QSlider::event qslider.cpp 359 0x4a39c8 10 QApplicationPrivate::notify_helper qapplication.cpp 3799 0x5ab73e 11 QApplication::notify qapplication.cpp 3762 0x5ab584 12 QCoreApplication::notifyInternal2 qcoreapplication.cpp 988 0xbb6187 13 QCoreApplication::sendEvent qcoreapplication.h 231 0xe425b3 14 QWidget::ensurePolished qwidget.cpp 10018 0x57b2f7 15 QWidget::ensurePolished qwidget.cpp 10027 0x57b36f 16 QWidget::ensurePolished qwidget.cpp 10027 0x57b36f 17 QWidget::ensurePolished qwidget.cpp 10027 0x57b36f 18 QWidget::event qwidget.cpp 8872 0x579b3b 19 QMainWindow::event qmainwindow.cpp 1543 0x4c8b46 20 QApplicationPrivate::notify_helper qapplication.cpp 3799 0x5ab73e 21 QApplication::notify qapplication.cpp 3762 0x5ab584 22 QCoreApplication::notifyInternal2 qcoreapplication.cpp 988 0xbb6187 23 QCoreApplication::sendEvent qcoreapplication.h 231 0xe425b3 24 QCoreApplicationPrivate::sendPostedEvents qcoreapplication.cpp 1649 0xbb73d3 25 QEventDispatcherWin32::sendPostedEvents qeventdispatcher_win.cpp 1294 0xb774c6 26 QWindowsGuiEventDispatcher::sendPostedEvents qwindowsguieventdispatcher.cpp 81 0x7a1677 27 qt_internal_proc(HWND__ *, unsigned int, unsigned int, long) *16 qeventdispatcher_win.cpp 443 0xb74782 28 USER32!RecordShutdownReason 0x75418233 29 USER32!DispatchMessageW 0x753ee638 30 USER32!DispatchMessageW 0x753ee103 31 USER32!DispatchMessageW 0x753edf50 32 QEventDispatcherWin32::processEvents qeventdispatcher_win.cpp 844 0xb75d0e 33 QWindowsGuiEventDispatcher::processEvents qwindowsguieventdispatcher.cpp 74 0x7a1645 34 QCoreApplication::processEvents qcoreapplication.cpp 1206 0xbb6667 35 delay midyax.cpp 1997 0x40ca37 36 MidyAX::getMidiMappingParamValues midyax.cpp 1505 0x409e9d 37 MidyAX::init midyax.cpp 316 0x404fd0 38 MidyAX::MidyAX midyax.cpp 110 0x40294e 39 qMain main.cpp 15 0x4016b5 40 WinMain *16 qtmain_win.cpp 123 0x43c290 41 main 0x1148ecd
The color slider event is not in the main thread and the slider has been created in the main thread. But the same code has been working before on Qt5.7/WIN10 and is working in DEBIAN8/Qt5.8, isn't that a bit abnormal ? or not.
I tried to get the call stack in the DEBIAN8/Qt5.8, but I can't get the program to breack --> must be a set-up issue were the debugger is not talled to use the debug lib or some other config problem. Not sure what to check in Qt Creator.
@PALYGAP said in Problem with QTimer --> get message "Object::startTimer: Timers cannot be started from another thread":
The color slider event is not in the main thread and the slider has been created in the main thread.
Whence the warning.
But the same code has been working before on Qt5.7/WIN10 and is working in DEBIAN8/Qt5.8
So? You have been depending on an implementation detail and got bitten, I don't see anything strange in this.
isn't that a bit abnormal ?
Not at all, refer to this quotation from the docs:
As mentioned, each program has one thread when it is started. This thread is called the "main thread" (also known as the "GUI thread" in Qt applications). The Qt GUI must run in this thread. All widgets and several related classes, for example QPixmap, don't work in secondary threads. A secondary thread is commonly referred to as a "worker thread" because it is used to offload processing work from the main thread.
You can't use widgets (here the polish events are the trigger) from different threads. It's not supported, it won't be supported and if it works then it's an implementation detail. You must serialize all GUI related events through the main thread's event loop. It is apparent from the stack traces you have a race condition deep in Qt's code, but that's because you're relying on an undocumented behaviour. You need to fix your code so all access to the widgets' routines is done from the main thread.
-
@PALYGAP said in Problem with QTimer --> get message "Object::startTimer: Timers cannot be started from another thread":
The color slider event is not in the main thread and the slider has been created in the main thread.
Whence the warning.
But the same code has been working before on Qt5.7/WIN10 and is working in DEBIAN8/Qt5.8
So? You have been depending on an implementation detail and got bitten, I don't see anything strange in this.
isn't that a bit abnormal ?
Not at all, refer to this quotation from the docs:
As mentioned, each program has one thread when it is started. This thread is called the "main thread" (also known as the "GUI thread" in Qt applications). The Qt GUI must run in this thread. All widgets and several related classes, for example QPixmap, don't work in secondary threads. A secondary thread is commonly referred to as a "worker thread" because it is used to offload processing work from the main thread.
You can't use widgets (here the polish events are the trigger) from different threads. It's not supported, it won't be supported and if it works then it's an implementation detail. You must serialize all GUI related events through the main thread's event loop. It is apparent from the stack traces you have a race condition deep in Qt's code, but that's because you're relying on an undocumented behaviour. You need to fix your code so all access to the widgets' routines is done from the main thread.
So? You have been depending on an implementation detail and got bitten, I don't see anything strange in this.
Did know I was doing that ... but that hurts anyway. :)
Thanks for the tips.
I might go back to the original design were the MIDI incoming events were dispatched to the main application window. Looks like that way the access the widget (sliders) was done in the main thread.
-
So? You have been depending on an implementation detail and got bitten, I don't see anything strange in this.
Did know I was doing that ... but that hurts anyway. :)
Thanks for the tips.
I might go back to the original design were the MIDI incoming events were dispatched to the main application window. Looks like that way the access the widget (sliders) was done in the main thread.
@PALYGAP said in Problem with QTimer --> get message "Object::startTimer: Timers cannot be started from another thread":
Did know I was doing that ... but that hurts anyway. :)
Truth hurts, man. ;)
I might go back to the original design were the MIDI incoming events were dispatched to the main application window. Looks like that way the access the widget (sliders) was done in the main thread.
Well, what about processing your events in the worker thread and from there raising a number of signals that are connected to the GUI? That's the usual way to do such things - process whatever's heavy and blocking and only notify the widgets about things they have to display (e.g. a progress bar change or something like this).
-
@PALYGAP said in Problem with QTimer --> get message "Object::startTimer: Timers cannot be started from another thread":
Did know I was doing that ... but that hurts anyway. :)
Truth hurts, man. ;)
I might go back to the original design were the MIDI incoming events were dispatched to the main application window. Looks like that way the access the widget (sliders) was done in the main thread.
Well, what about processing your events in the worker thread and from there raising a number of signals that are connected to the GUI? That's the usual way to do such things - process whatever's heavy and blocking and only notify the widgets about things they have to display (e.g. a progress bar change or something like this).
@kshegunov said in Problem with QTimer --> get message "Object::startTimer: Timers cannot be started from another thread":
Well, what about processing your events in the worker thread and from there raising a number of signals that are connected to the GUI? That's the usual way to do such things - process whatever's heavy and blocking and only notify the widgets about things they have to display (e.g. a progress bar change or something like this).
Good idea, didn't thought about it. I'll try it tomorrow.
Thanks.