I have a code with a QDoubleSpinBox
ui->doubleSpinBoxExposure->setMinimum(0.001);
ui->doubleSpinBoxExposure->setMaximum(1000);
ui->doubleSpinBoxExposure->setSingleStep(1.0);
connect(ui->doubleSpinBoxExposure, SIGNAL(valueChanged(double)),
this, SLOT(OndoubleSpinBoxExposure_valueChanged(double)));
void WidgetCameraParameter::OndoubleSpinBoxExposure_valueChanged(double value)
{
if (!camera)
return;
if (camera->isOpen())
{
float exposure = static_cast<float>(value);
float cameraExposure;
camera->setExposure(exposure);
LOG_INFO() <<" setting exposure to " << value << " ms";
cameraExposure = camera->exposure();
LOG_INFO() <<" resulting exposure is " << cameraExposure << " ms";
}
}
The problem is, when I step up in the gui or down, this happens twice.
The starting parameter is value = 2. StepUp calls this function with 3, and directly afterwards with 4. And I have no idea why.
The stack trace is not helpfull:
1 WidgetCameraParameter::OndoubleSpinBoxExposure_valueChanged widgetcameraparameter.cpp 311 0x406c17
2 WidgetCameraParameter::qt_static_metacall moc_widgetcameraparameter.cpp 110 0x40811f
3 QMetaObject::activate qobject.cpp 3771 0x12bc2e1
4 QMetaObject::activate qobject.cpp 3633 0x12bc575
5 QDoubleSpinBox::valueChanged moc_qspinbox.cpp 436 0x15e66190
6 QDoubleSpinBoxPrivate::emitSignals qspinbox.cpp 1112 0x15e663b2
7 QAbstractSpinBoxPrivate::setValue qabstractspinbox.cpp 1741 0x15e6174d
8 QAbstractSpinBox::stepBy qabstractspinbox.cpp 643 0x15e62aba
9 QAbstractSpinBox::timerEvent qabstractspinbox.cpp 1246 0x15e5ffea
10 QObject::event qobject.cpp 1232 0x12bc918
11 QWidget::event qwidget.cpp 9347 0x15d0c544
12 QAbstractSpinBox::event qabstractspinbox.cpp 795 0x15e65930
13 QApplicationPrivate::notify_helper qapplication.cpp 3727 0x15cc85ca
14 QApplication::notify qapplication.cpp 3690 0x15cd1f4f
15 QCoreApplication::notifyInternal2 qcoreapplication.cpp 1048 0x1295119
16 QCoreApplication::sendEvent qcoreapplication.h 234 0x12e4d87
17 QEventDispatcherWin32Private::sendTimerEvent qeventdispatcher_win.cpp 447 0x12e4d87
18 qt_internal_proc(HWND__ *, unsigned int, unsigned int, long) *16 qeventdispatcher_win.cpp 242 0x12e53d5
19 gapfnScSendMessage 0x771162fa
20 ?? 0x5c0f30
21 USER32!GetThreadDesktop 0x77116d3a
22 QEventDispatcherWin32Private::sendTimerEvent qeventdispatcher_win.cpp 456 0x12e4dc9
23 ?? 0x5c0f30
24 USER32!CharPrevW 0x771177c4
25 USER32!DispatchMessageW 0x7711788a
26 QEventDispatcherWin32::processEvents qeventdispatcher_win.cpp 629 0x12e4ae8
27 QWindowsGuiEventDispatcher::processEvents qwindowsguieventdispatcher.cpp 74 0x2496dab7
28 QEventLoop::processEvents qeventloop.cpp 136 0x12937c8
29 QEventLoop::exec qeventloop.cpp 214 0x1293c20
30 QCoreApplication::exec qcoreapplication.cpp 1336 0x129c30e
31 QGuiApplication::exec qguiapplication.cpp 1761 0x8461552
32 QApplication::exec qapplication.cpp 2901 0x15cc84a9
33 qMain main.cpp 28 0x40183d
34 WinMain *16 qtmain_win.cpp 104 0x4094c5
35 main 0x4179ad
Any idea how to debug this further?
EDIT:
This only happens when I debug with breakpoints in the slot. Without the slot is only called once.
The second call of the slot does not happen from any function within the slot function, but only after the slot has ended from the event loop.
You can loop at the complete code:
https://github.com/pospiech/code/tree/master/libdev/devices/CameraViewer
Looking at the QStyle::StyleHint enum, there is an interesting SH_SpinBox_ClickAutoRepeatThreshold constant. You can check its current value for your spin box, like this:
qDebug() << ui->doubleSpinBoxExposure->style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatThreshold);
This generally returns 500, which is the number of milliseconds after which the auto repeat gets triggered (i.e. if the user holds the mouse press on the up spin button for longer than that threshold, the spin box value will start increasing continuously).
To see if you have a timing issue, try changing that value, using a custom QStyle class like this:
#include <QProxyStyle>
class MyStyle : public QProxyStyle
{
public:
int styleHint(StyleHint stylehint, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *returnData) const
{
if(stylehint == QStyle::SH_SpinBox_ClickAutoRepeatThreshold)
{
return 2000; //2 seconds threshold
}
return QProxyStyle::styleHint(stylehint, opt, widget, returnData);
}
};
and setting an instance of it to the spin box style:
ui->doubleSpinBoxExposure->setStyle(new MyStyle());
Now it takes a lot (two long seconds) before the auto repeat gets triggered, and your issue should be gone, accordingly.
It looks like you have a freezing gui-thread with your slot.
You can try this code in your slot
void WidgetCameraParameter::OndoubleSpinBoxExposure_valueChanged(double value)
{
#define NUM_LOOPS 1000000000
qDebug() << value;
quint64 i = NUM_LOOPS;
while(i--);
}
To avoid this, you have to move to another thread an operation that consumes a lot of CPU time.
In debug mode its because of autorepeating timer.
Try this code to disable autorepeating in debug and, i think, you`ll understand:
*.h
...
#ifdef QT_DEBUG
bool eventFilter(QObject *watched, QEvent *event) override;
#endif
...
*.c
...
ui->setupUi(this);
#ifdef QT_DEBUG
ui->doubleSpinBoxExposure->installEventFilter(this);
#endif
...
#ifdef QT_DEBUG
bool WidgetCameraParameter::eventFilter(QObject *watched, QEvent *event)
{
QDoubleSpinBox *castSBox = static_cast<QDoubleSpinBox*>(watched);
if(castSBox && event->type()==QEvent::Timer)
{
QTimerEvent *tEvent = static_cast<QTimerEvent*>(event);
if(tEvent)
qDebug() << "<--QEvent::Timer-->" << tEvent->timerId();
return true;
}
return QObject::eventFilter(watched,event);
}
#endif
Related
So I am using WebEngineView in my QML like this:
...
Loader {
// some properties
sourceComponent: WebEngineView {
...
}
}
In the c++ logic I am using QQuickWebEngineProfile::defaultProfile() in the constructor and destructor
MainViewModel(QObject* parent) : QObject(parent)
{
// using QQuickWebEngineProfile::defaultProfile();
// getting cookieStore of the profile and connect it to some slots
}
~MainViewModel()
{
// using QQuickWebEngineProfile::defaultProfile();
// getting cookieStore of the profile and disconnect it from MainViewModel
}
So it's working perfectly, but when I am trying to close my app (calling qApp->quit()), it crashes. If I remove WebEngineView from QML it works, if I remove using of defaultProfile() in c++ it works. But I need these things.
Dump:
1 _threadid ucrtbased 0x7ffb48687c75
2 _threadid ucrtbased 0x7ffb48687e13
3 abort ucrtbased 0x7ffb4869e01d
4 `anonymous namespace'::messageHandler application.cpp 46 0x7ff7c2d2b1bf
5 qt_message_print qlogging.cpp 1844 0x7ffb08317fdf
6 qt_message qlogging.cpp 379 0x7ffb08318657
7 QMessageLogger::fatal qlogging.cpp 890 0x7ffb08316612
8 qt_assert qglobal.cpp 3354 0x7ffb08307a48
9 QAccessible::registerAccessibleInterface qaccessible.cpp 747 0x7ffb01df22bd
10 QAccessible::uniqueId qaccessible.cpp 767 0x7ffb01df2247
11 QQuickWebEngineViewPrivate::widgetChanged qquickwebengineview.cpp 982 0x7ffb4b2b5bda
12 QQuickWebEngineViewPrivate::bindViewAndWidget qquickwebengineview.cpp 972 0x7ffb4b2b5b6e
13 QQuickWebEngineViewPrivate::releaseProfile qquickwebengineview.cpp 200 0x7ffb4b2b2349
14 QtWebEngineCore::ProfileAdapter::~ProfileAdapter profile_adapter.cpp 127 0x7ffad4237f20
15 QtWebEngineCore::ProfileAdapter::`vector deleting destructor' Qt5WebEngineCored 0x7ffad4238678
16 std::default_delete<QtWebEngineCore::DevToolsFrontendQt::NetworkResourceLoader>::operator() memory 1758 0x7ffad41d9a75
17 std::unique_ptr<QtWebEngineCore::WebChannelIPCTransportHost,std::default_delete<QtWebEngineCore::WebChannelIPCTransportHost>>::reset memory 1910 0x7ffad4287857
18 QtWebEngineCore::WebEngineContext::destroy web_engine_context.cpp 339 0x7ffad4295a87
19 QtWebEngineCore::WebEngineContext::destroyContextPostRoutine web_engine_context.cpp 425 0x7ffad4295bf8
20 qt_call_post_routines qcoreapplication.cpp 336 0x7ffb087276ef
21 QApplication::~QApplication qapplication.cpp 714 0x7ffb07767046
...
30 main main.cpp 63 0x7ff7c21d4640
It tried to access main window which at that moment has already been deleted. To resolve this problem I had to delay destruction of my main window. I've done it with
QObject::deleteLater()
I have a simple program that reads an image from a camera and converts it to Qimage. This is then converted into a pixmap which is supposed to be drawn in paintEvent(QPaintEvent * event)
The problem is that the program crashes when the widget is drawn. Here while leaving on_pushButtonTakeImage_clicked()
This is the basic code:
void MainWindow::on_pushButtonTakeImage_clicked()
{
bool isReady = camera->initialize();
if (isReady){
camera->openCamera();
camera->capture();
ui->widgetCameraImage->setImage(camera->image());
}
}
void QCameraImageBase::setImage(const QImage & image)
{
Q_D(QCameraImageBase);
d->pixmap = QPixmap::fromImage(image);
update(); // calls paintEvent
}
The debuggin point within the overloaded paintEvent(QPaintEvent * event) is never called.
This is the trace
1 ntdll!RtlQueryPerformanceCounter 0x77603266
2 ntdll!RtlQueryPerformanceCounter 0x776034a1
3 ntdll!RtlpNtEnumerateSubKey 0x776a10c3
4 ntdll!RtlUlonglongByteSwap 0x7765abe2
5 ?? 0x1a830000
6 ntdll!RtlQueryPerformanceCounter 0x776034a1
7 msvcrt!malloc 0x77149d45
8 libstdc++-6!_Znwj 0x7c999a
9 QRasterPaintEngine::createState qpaintengine_raster.cpp 686 0xd5f469
10 QPainter::begin qpainter.cpp 1754 0xd6f375
11 QPainter::QPainter qpainter.cpp 1476 0xd6fc60
12 QWidgetPrivate::drawWidget qwidget.cpp 5560 0xe1a4012
13 QWidgetBackingStore::doSync qwidgetbackingstore.cpp 1375 0xe177a66
14 QWidgetBackingStore::sync qwidgetbackingstore.cpp 1156 0xe177e95
15 QWidgetPrivate::syncBackingStore qwidget.cpp 1951 0xe19181c
16 QWidget::event qwidget.cpp 9216 0xe1ac102
17 QMainWindow::event qmainwindow.cpp 1342 0xe2c8ac0
18 QApplicationPrivate::notify_helper qapplication.cpp 3732 0xe1686de
19 QApplication::notify qapplication.cpp 3695 0xe172093
20 QCoreApplication::notifyInternal2 qcoreapplication.cpp 1050 0x6bb0b5d1
... <Mehr>
I work with Qt Creator and mingw. Anything I can do to fix this error or find more about the cause?
The following snippet from a long long bunch of C++ sources and header files (which I will be happy to share in case they are needed) shows the user-defined function(or object?) Read being called as part of a Multi-threading operation that is going on.
As part of identifying the problem, I printed flags just before and after the function is called:
std::cout<<"Before calling\n";
and
std::cout<<"After calling\n";
I have also inserted a flag to be printed just after the function is called:
std::cout<<"Entered the function";
The entire application compiles perfectly and also runs smoothly - until this function Read is called, it never gets executed.
In the output, you get the "Before calling" and "After calling" but never the "Entered function".
Operating system used is Ubuntu 16.04, with the g++ compiler.
As of now I am only sharing two snippets related to the question - (since a single file is around 1500 lines of code; I think it should suffice, let me know if otherwise)
Following is the snippet of the thread in which function is called (at line 130) and then is the other file where the function is defined.
Thread where the Function is called:
1 void* StartGenericReadThread(void *ThreadAr)
2 { //std::cout<<"flag GenericThread\n";
3 //printf("\nSuccess");
4 int PORT = ((ThreadArg*)ThreadAr)->PORT;
5 #ifdef WIN32
6 Sleep(4000);
7 #else
8 sleep(4);
9 #endif
10 DSDMux *Mux;
11 DSDConfigReader *cfg;
12 SNMPTrap Trap;
13 DSDMessageSender *DMS;
14 Mux = ((ThreadArg*)ThreadAr)->Mux;
15 cfg = ((ThreadArg*)ThreadAr)->cfg;
16 DMS = ((ThreadArg*)ThreadAr)->MSG;
17
18
19 strcpy(DMS->SNMP_DET.DSD_MAN_IP,cfg->DSDSetting.DSD_MANAGER_IP);
20 strcpy(DMS->SNMP_DET.SNMP_MAN_IP,cfg->DSDSetting.SNMP_TRAP_IP);
21 DMS->SNMP_DET.SNMP_MAN_PORT = cfg->DSDSetting.SNMP_TRAP_PORT;
22 DMS->SNMP_DET.DSD_MAN_PORT = 162;
23
24 if ( checkflag != 1) //EDITED
25 {std::cout<<"\nDSD Manager IP set to
26 "<<cfg->DSDSetting.DSD_MANAGER_IP<<"\n";
27 std::cout<<"SNMP TRAP IP set to
28 "<<cfg->DSDSetting.SNMP_TRAP_IP<<"\n";
29
30 std::cout<<"SNMP TRAP PORT set to "<<cfg->DSDSetting.SNMP_TRAP_PORT<<"\n";
31 checkflag=1;
32 }
33
34 try
35 { //std::cout<<"Entered try\n";
36 bool IPLostErrSet(false),IPGainset(false),FIFOreaderr(false);
37 //DSDCo
38 int nStatus, nLatched,inFifoLoad,MaxBuffRead,lostCount(0);
39 dr = theInput[PORT].SetRxControl(DTAPI_RXCTRL_RCV);
40
41 if ( DTAPI_OK != dr )
42 { //std::cout<<"\nSetRXControl is not OK";
43 // return NULL; EDITED
44 }
45
46 #ifdef WIN32
47 while(!_kbhit())
48 #else
49 while(1)
50 #endif
51 { //EDITED
52 //MaxBuffRead=(inFifoLoad/188)*188;
53 //int DmaSize = ( inFifoLoad > c_ReadBufferSize ) ? c_ReadBufferSize : MaxBuffRead;
54
55 theInput[PORT].GetFlags(nStatus, nLatched);
56 if ( 0 != (DTAPI_RX_FIFO_OVF & nLatched) )
57 {
58 printf("Fifo overflow for input port %d\t\t\t\t\t[Error]\n",PORT+1);
59 DMS->SendLog(FIFO_OVERFLOW,PORT+1);
60 theInput[PORT].ClearFifo();
61 dr = theInput[PORT].SetRxControl(DTAPI_RXCTRL_RCV);
62 if ( DTAPI_OK != dr )
63 {
64 printf("\nError");
65
66 }
67 else
68 DMS->SendLog(FIFO_OVERFLOW_CLR,PORT+1);
69 }
70 theInput[PORT].GetFifoLoad(inFifoLoad);
71 inFifoLoad = MINBUFFSIZE + 512;
72 if (inFifoLoad < MINBUFFSIZE+512)
73 {
74 lostCount++;
75 if(lostCount>1000&&!IPLostErrSet)
76 {
77 lostCount=0;
78 printf("\nInput lost on port %d\t\t\t\t\t\t[ERROR]",PORT+1);
79
80 DMS->SendLog(INPUT_LOST,PORT+1);
81 int pid;
82 /*for(pid=21;pid<8191;pid++)
83 {
84 if(cfg->MuxCfg.PORT[PORT].PID[pid].Mux)
85 DMS->SendLog(PID_REMUX_ERR,pid,PORT+1);
86 }*/
87 Mux->PSI.PATdata.Table[PORT].Section[0].no_of_programs = 0;
88 IPGainset = false;
89 IPLostErrSet = true;
90 }
91
92 #ifdef WIN32
93 Sleep(1);
94 #else
95 usleep(1000);
96 #endif
97 continue;
98 }
99 lostCount = 0;
100 //std::cout<<"\nWill check for IPGAINSET now\n";
101 if(!IPGainset)
102 { //std::cout<<"IPGAINSET IS FALSE\n";
103 cfg->OutputConf.Status=true;
104 printf("\nInput signal detected on port %d\t\t\t\t\t[ OK ]",PORT+1);
105
106 DMS->SendLog(INPUT_GAIN,PORT+1);
107 /*int pid;
108 for(pid=21;pid<8191;pid++)
109 {
110 if(cfg->MuxCfg.PORT[PORT].PID[pid].Mux)
111 {
112 //std::cout<<pid;
113 DMS->SendLog(PID_REMUX,pid,PORT+1);
114 }
115 };*/
116 IPLostErrSet = false;
117 IPGainset = true;
118 }
119 //std::cout<<"IPGAINSET is TRUE\n";
120 //printf("\t%d",inFifoLoad);
121 MaxBuffRead=(inFifoLoad/188)*188;
122 int DmaSize = ( inFifoLoad > c_ReadBufferSize ) ? c_ReadBufferSize : MaxBuffRead;
123
124 // fifold=(int)DmaSize;
125 // char data[65424*10];
126
127
128 std::cout<<"Before Calling\n";
129
130 dr = theInput[PORT].Read(Mux->TSPacket[PORT].data,DmaSize);
131
132 std::cout<<"After Calling\n";
133
134 if ( DTAPI_OK != dr )
135 {// std::cout<<"Error in executing Read function\n";
136 if(!FIFOreaderr)
137 DMS->SendLog(FIFO_READ_ERR,dr,PORT+1);
138
139 }
140 else
141 {
142 Mux->ParseAndMuxTS(PORT,DmaSize,cfg,fs);
143
144 }
145 }
146 return NULL;
147
148 }
149 catch(...)
150 {
151 // printf("Error in StartGenericReadThread\n");
152 DMS->SendLog(INTERNAL_ERR,0,0,0,"StartGenericReadThread");
153 return NULL;
154 }
155 }
Now following is the snippet of the function definition (which is in another file):
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "DTAPI.h"
#include "DtapiUtility.h"
#include "Dta1xxIoCtl.h"
#include "Dta1xxCodes.h"
#include "Dtu2xxIoCtl.h"
#include "Dtu2xxCodes.h"
#include <iostream>
//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ TsInpChannel implementation +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- TsInpChannel::Read -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
//
// Read data bytes from the input channel using DMA transfers.
//
DTAPI_RESULT TsInpChannel::Read(
char* pBuffer, // [in] Pointer to data to be read from Device
int NumBytesToRead) // [in] Number of bytes to be read from Device
{
std::cout<<"Entered the function\n";
// Must be attached.
//if (!m_Attached) EDITED
// return DTAPI_E_NOT_ATTACHED; EDITED
// Validity check on parameters
if (NumBytesToRead<0 || NumBytesToRead%4!=0)
return DTAPI_E_INVALID_SIZE;
if ((atoi)(pBuffer)%4 != 0)
return DTAPI_E_INVALID_BUF;
// Avoid strange effects when NumBytesToRead is zero
if (NumBytesToRead == 0)
return DTAPI_OK;
DTAPI_RESULT dr;
// Processing is dependent on device category
if (m_HwFuncDesc.m_DvcDesc.m_Category == DTAPI_CAT_PCI) {
//-.-.-.-.-.-.-.-.-.- Call the appropiate device IoCtl handler -.-.-.-.-.-.-.-.-.-
DTA1XX_IOCTL_DATA iod;
memset(&iod, 0, sizeof(DTA1XX_IOCTL_DATA));
iod.m_nChIdx = GetIndexOnDevice();
iod.m_Data.m_DataTransDesc.m_pBuffer = pBuffer;
iod.m_Data.m_DataTransDesc.m_nNumBytesToTr = NumBytesToRead;
dr = ioctl(m_fdDevice, DTA1XX_IOCTL_DMA_USERMEM_READ, &iod);
if ( dr != DTAPI_OK )
return dr;
}
else if (Category() == DTAPI_CAT_USB) {
// Read using file IO
int ret = read(m_fdDevice, pBuffer, NumBytesToRead);
if ( ret < 0 )
return DTAPI_E_DEV_DRIVER;
}
else //EDITED
{ std::cout<<"\n Beginning to read file at /home/rtpl/Desktop/ts.mp4";
char * storedfilepath = "/home/rtpl/Desktop/ts.mp4";
int *vedant = open(storedfilepath,O_RDONLY);
int ret = read(vedant, pBuffer, NumBytestoRead);
if ( ret < 0)
std::cout<<"\n File contents cannot be read";
//return DTAPI_E_INTERNAL; // Unknown device category
}
return DTAPI_OK;
}
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- TsInpChannel::ReadDirect -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
//
DTAPI_RESULT TsInpChannel::ReadDirect(
char* pBuffer, // [in] Buffer to store data
int NumBytesToRead, // [in] Number of bytes to be read
int& NumBytesRead) // [out] Number of bytes read
{
return DTAPI_E_NOT_SUPPORTED;
}
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.- TsInpChannel::ReadUsingDma -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
//
// Old name of Read. Still here for backward compatibility.
//
DTAPI_RESULT TsInpChannel::ReadUsingDma(
char* pBuffer, // [in] Buffer to store data
int NumBytesToRead) // [in] Number of bytes to be written to PCI card
{
return Read(pBuffer, NumBytesToRead);
}
I know that you need to reimplement the QApplication::notify() method to properly catch exceptions thrown from the main thread's event handlers.
But what about other threads? Say, I have an object with a slot, and this object lives in a QThread (with default run() method, which just calls exec()), i.e. the thread affinity of this object is the background QThread. So, where should I catch exceptions thrown from this object's slot?
IOW, how do I reimplement the notify() method of a background thread?
When you create your Custom Application with overriden notify method; the QThread you create uses this overriden method too (as the main thread) once it has started its own event loop
It means in practice that if you connect any slot to the QThread::started signal; then this slot executes outside the event loop of thethread, thus not in the overriden notify method.
Here is a sample of code that helps to understand what happen:
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QThread>
#include <QTimer>
#include <exception>
class ThrowingObject : public QObject
{
public:
void doThrowInNotify()
{
qDebug() << "I am execution on thread id" << QThread::currentThreadId() << " and I am throwing";
throw std::exception("KBOOOM");
}
void scheduleThrow()
{
QTimer* singleShot = new QTimer(this);
singleShot->setSingleShot(true);
connect(singleShot, &QTimer::timeout, this, &ThrowingObject::doThrow);
singleShot->start();
qDebug() << "I am execution on thread id" << QThread::currentThreadId() << " and I will throw in run";
}
void doThrow()
{
qDebug() << "I am execution on thread id" << QThread::currentThreadId() << " and I am throwing right now";
//This exception is not catched, and definitly crash the process
throw std::exception("KBOOOM");
}
void doThrowOutsideNotify()
{
//wait 5s for demo purpose, this slot is called by Object2, after Object1 throw in thread1 event loop
QThread::sleep(5);
qDebug() << "I am execution on thread id" << QThread::currentThreadId() << " and I am throwing right now";
//This exception is not catched, and definitly crash the process
throw std::exception("FATAL KBOOOM");
}
};
class ApplicationWithExceptionCatchedInNotify : public QApplication
{
public:
ApplicationWithExceptionCatchedInNotify(int argc, char *argv[]) :
QApplication(argc,argv)
{}
bool notify(QObject* receiver, QEvent *e) override
{
try {
return QApplication::notify(receiver, e);
}
catch(std::runtime_error e)
{
qDebug() << "std::runtime_error in thread : " << QThread::currentThreadId();
qDebug() << e.what();
}
catch(std::exception e)
{
qDebug() << "std::exception in thread : " << QThread::currentThreadId();
qDebug() << e.what();
}
catch(...)
{
qDebug() << "exception thread : " << QThread::currentThreadId();
}
qDebug() << "catch in notify ";
return false;
}
};
int main(int argc, char *argv[])
{
ApplicationWithExceptionCatchedInNotify app(argc, argv);
qDebug() << "Main QThread id" << QThread::currentThreadId();
//Object o1 will throw in its event loop (in notify)
QThread thread1;
ThrowingObject o1;
o1.moveToThread(&thread1);
QObject::connect(&thread1, &QThread::started, &o1, &ThrowingObject::scheduleThrow);
thread1.start();
//Object o2 will throw before the event loop is installed
QThread thread2;
ThrowingObject o2;
o2.moveToThread(&thread2);
//Connect to started signal.
QObject::connect(&thread2, &QThread::started, &o2, &ThrowingObject::doThrowOutsideNotify);
thread2.start();
app.exec();
}
Running this code sample on windows , Qt 5.9 with Qt creator gives for example :
Output :
Main QThread id 0x11e4
I am execution on thread id 0x180c and I will throw in run
I am execution on thread id 0x180c and I am throwing right now
std::exception in thread : 0x180c
KBOOOM
catch in notify
I am execution on thread id 0x27b8 and I am throwing right now
and a Microsoft Visual Studio Runtime Library pop up crying that :
Microsoft Visual C++ Runtime Library
Debug Error!
Program: ...ad-Desktop_Qt_5_9_2_MSVC2017_64bit-Debug\debug\DemoThread.exe
abort() has been called
(Press Retry to debug the application)
If you put breakpoint; once can realize that :
Object o1 throws in QThread::exec methods, going down the callstack we can see we are in ApplicationWithExceptionCatchedInNotify::Notify
1 ThrowingObject::doThrow main.cpp 35 0x7ff66615352b
2 QtPrivate::FunctorCall,QtPrivate::List<>,void,void (__cdecl ThrowingObject:: *)(void) __ptr64>::call qobjectdefs_impl.h 136 0x7ff66615358c
3 QtPrivate::FunctionPointer::call,void> qobjectdefs_impl.h 170 0x7ff666152ce7
4 QtPrivate::QSlotObject,void>::impl qobject_impl.h 121 0x7ff66615363e
5 QtPrivate::QSlotObjectBase::call qobject_impl.h 101 0x54a82428
6 QMetaObject::activate qobject.cpp 3754 0x54a70ee0
7 QMetaObject::activate qobject.cpp 3629 0x54a707a8
8 QTimer::timeout moc_qtimer.cpp 202 0x54a8f739
9 QTimer::timerEvent qtimer.cpp 257 0x54a8f79a
10 QObject::event qobject.cpp 1228 0x54a72b73
11 QApplicationPrivate::notify_helper qapplication.cpp 3722 0x53aeb8ee
12 QApplication::notify qapplication.cpp 3094 0x53ae6323
13 ApplicationWithExceptionCatchedInNotify::notify main.cpp 60 0x7ff666158730
14 QCoreApplication::notifyInternal2 qcoreapplication.cpp 1018 0x54a1b0c6
15 QCoreApplication::sendEvent qcoreapplication.h 233 0x54a26062
16 QEventDispatcherWin32::event qeventdispatcher_win.cpp 1041 0x54ad8cab
17 QApplicationPrivate::notify_helper qapplication.cpp 3722 0x53aeb8ee
18 QApplication::notify qapplication.cpp 3094 0x53ae6323
19 ApplicationWithExceptionCatchedInNotify::notify main.cpp 60 0x7ff666158730
20 QCoreApplication::notifyInternal2 qcoreapplication.cpp 1018 0x54a1b0c6
21 QCoreApplication::sendEvent qcoreapplication.h 233 0x54a26062
22 QCoreApplicationPrivate::sendPostedEvents qcoreapplication.cpp 1678 0x54a1c982
23 QEventDispatcherWin32::sendPostedEvents qeventdispatcher_win.cpp 1064 0x54ad8e6a
24 qt_internal_proc qeventdispatcher_win.cpp 237 0x54ad6b47
25 CallWindowProcW USER32 0x7ffba1571c24
26 DispatchMessageW USER32 0x7ffba157156c
27 QEventDispatcherWin32::processEvents qeventdispatcher_win.cpp 628 0x54ad755b
28 QEventLoop::processEvents qeventloop.cpp 135 0x54a15498
29 QEventLoop::exec qeventloop.cpp 212 0x54a156de
30 QThread::exec qthread.cpp 515 0x5465028f
31 QThread::run qthread.cpp 583 0x546501c3
32 QThreadPrivate::start qthread_win.cpp 380 0x5465caed
33 BaseThreadInitThunk KERNEL32 0x7ffb9f5b8364
34 RtlUserThreadStart ntdll 0x7ffba1bb7091
Object o2 throws in QThread::start methods; outside of the thread2 event loop
1 ThrowingObject::doThrowOutsideNotify main.cpp 45 0x7ff666152ba6
2 QtPrivate::FunctorCall,QtPrivate::List<>,void,void (__cdecl ThrowingObject:: *)(void) __ptr64>::call qobjectdefs_impl.h 136 0x7ff66615358c
3 QtPrivate::FunctionPointer::call,void> qobjectdefs_impl.h 170 0x7ff666152ce7
4 QtPrivate::QSlotObject,void>::impl qobject_impl.h 121 0x7ff66615363e
5 QtPrivate::QSlotObjectBase::call qobject_impl.h 101 0x54a82428
6 QMetaObject::activate qobject.cpp 3754 0x54a70ee0
7 QMetaObject::activate qobject.cpp 3629 0x54a707a8
8 QThread::started moc_qthread.cpp 160 0x54650149
9 QThreadPrivate::start qthread_win.cpp 377 0x5465cad6
10 BaseThreadInitThunk KERNEL32 0x7ffb9f5b8364
11 RtlUserThreadStart ntdll 0x7ffba1bb7091
Since certain version of Qt5, the QCoreApplication::notify manual says:
this function is called for all events sent to any object in any
thread.
So this means that the correct answer to my original question was "just do what you were doing all along".
Funnily, just as I discovered this, this newly discovered knowledge instantly became outdated by this phrase from the very same manual:
This function will not be called for objects that live outside the
main thread in Qt 6. Applications that need that functionality should
find other solutions for their event inspection needs in the meantime.
The change may be extended to the main thread, causing this function
to be deprecated.
LOL. I have not migrated to Qt6 yet so I have no idea what's the situation there, but when I do, I might just re-open this exact question.
After googling around I found out that segmentation faults are given when the program is pointed to use memory that it doesn’t have access to.
I’ve recently started experiencing these errors after I tried making a custom button class that would enclose, in its clicked() signal, an integer.
Here’s the custom button class:
.h:
#include <QtGui>
#ifndef CUSTOMBUTTON_H
#define CUSTOMBUTTON_H
class CustomButton : public QPushButton //This simple class allows us to map arguments in the Widget's cicked() signal.
{ //In the project, it's used in the delete-edit buttons so the program knows which part of the Movie/Theater/Screening list we're referring to
Q_OBJECT
public:
CustomButton(QString name,int num, QWidget *parent = 0);
signals:
void clicked(int pos);
private:
QSignalMapper *signalMapper;
};
#endif // CUSTOMBUTTON_H
.cpp:
#include "custombutton.h"
CustomButton::CustomButton(QString name,int num = 0, QWidget *parent) //Our constructor
: QPushButton(name,parent)
{ //Our button's now created and shown, through the superconstructor. Let's take care of its clicked() signal.
signalMapper = new QSignalMapper(this);
connect(this, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(this, num);
connect(signalMapper, SIGNAL(mapped(int)),this, SIGNAL(clicked(int)));
}
And then in my main code I do:
CustomButton *edit_button = new CustomButton("Edit",i,0);
edit_button->setFixedWidth(30);
connect(edit_button,SIGNAL(clicked(int)),this,SLOT(edit_movie(int))); //When the user decides to edit a movie, we set the class'es working_with var to the position of the film in the MovieList and we set the screen to the appropriate one.
CustomButton *del_button = new CustomButton("Delete",i,0); //We pass i as an argument to the button, so it can relate to the movie it's set next to.
del_button->setFixedWidth(45);
connect(del_button,SIGNAL(clicked(int)),this,SLOT(del_movie(int)));
Where i is the number I want it to have in the signal.
Thing is, thorugh the debugger it doesn’t give me a segfault if I press the Delete button. It all happens in the edit one.
As I’m still pretty confused and in a situation where I don’t even know WHAT to ask about, if you need anything else from me please say so and I will provide.
Here’s the backtrace, which I know not how to read:
0 QHash<QObject*, QString>::findNode qhash.h 884 0×69e98594
1 QHash<QObject*, QString>::contains qhash.h 874 0×69e98568
2 QSignalMapper::map qsignalmapper.cpp 267 0×69debe0c
3 QSignalMapper::map qsignalmapper.cpp 257 0×69debda2
4 QSignalMapper::qt_static_metacall moc_qsignalmapper.cpp 64 0×69debfce
5 QMetaObject::activate qobject.cpp 3547 0×69de9baf
6 QAbstractButton::clicked moc_qabstractbutton.cpp 220 0×10cb4b8
7 QAbstractButtonPrivate::emitClicked qabstractbutton.cpp 548 0xe2e517
8 QAbstractButtonPrivate::click qabstractbutton.cpp 541 0xe2e495
9 QAbstractButton::mouseReleaseEvent qabstractbutton.cpp 1123 0xe2f941
10 QWidget::event qwidget.cpp 8362 0xae63de
11 QAbstractButton::event qabstractbutton.cpp 1082 0xe2f7cc
12 QPushButton::event qpushbutton.cpp 683 0xecfeba
13 QApplicationPrivate::notify_helper qapplication.cpp 4554 0xa9c020
14 QApplication::notify qapplication.cpp 4097 0xa9a26a
15 QCoreApplication::notifyInternal qcoreapplication.cpp 876 0×69dd3b76
16 QCoreApplication::sendSpontaneousEvent qcoreapplication.h 234 0×113137e
17 QApplicationPrivate::sendMouseEvent qapplication.cpp 3163 0xa98ad6
18 QETWidget::translateMouseEvent qapplication_win.cpp 3363 0xb03171
19 QtWndProc qapplication_win.cpp 1696 0xafdf66
20 USER32!IsDialogMessageW C:\Windows\syswow64\user32.dll 0 0×76726238
21 USER32!RegisterSystemThread C:\Windows\syswow64\user32.dll 0 0×767278b0
22 ?? 0 0×30000
23 USER32!AllowForegroundActivation C:\Windows\syswow64\user32.dll 0 0×767268ea
24 qt_is_translatable_mouse_event qapplication_win.cpp 1463 0xafd465
25 USER32!GetMessageExtraInfo C:\Windows\syswow64\user32.dll 0 0×76727d31
26 ?? 0
Any heads up as to what might be causing the problem? As I said, the segfault only occurs if I run the program through the Debugger and when I press the "Edit" button, of the CustomButton class. When I normally build&run, the program works 9/10 times. Sometimes, clicking the edit button results in a crash. This erratic behaviour is what caused me to look for help here.
As when I click the button I'm taken to a new screen, I'm suspecting that the problem might lie in the decstructor? Does a blank destructor correctly deconstruct elements of objects of the CustomButton class, seeing as the actual object is passed to the base class constructor? Maybe I've got a leak there?
Unless knowing where you create the objects, it's hard to tell why there is a segfault in QSignalMapper. The pointer to your signal mapper might be invalid at some point in time, so there might be an unwanted deletion.
In some cases, a complete rebuild of your application might be helpful. Also re-running qmake. Just should be on your checklist when you can't explain why there is a segfault ...;)
There is an alternative to QSignalMapper: keep your signal clicked(int) and implement a private slot:
private slots:
this_clicked() {
emit clicked(num);
}
Then put in the constructor:
connect(this, SIGNAL(clicked()), SLOT(this_clicked()));