我知道您需要重新實現QApplication :: notify()方法來正確捕獲從主線程的事件處理程序拋出的異常。 但其他線程呢?比方說,我有一個插槽的對象,並且此對象位於QThread中(使用默認的run()方法,該方法只調用exec()),即該對象的線程關聯性是背景QThread。那麼,我應該在哪裏捕獲從該對象的插槽拋出的異常呢?Qt:處理從後臺線程處理程序拋出的異常
IOW,如何重新實現後臺線程的notify()方法?
我知道您需要重新實現QApplication :: notify()方法來正確捕獲從主線程的事件處理程序拋出的異常。 但其他線程呢?比方說,我有一個插槽的對象,並且此對象位於QThread中(使用默認的run()方法,該方法只調用exec()),即該對象的線程關聯性是背景QThread。那麼,我應該在哪裏捕獲從該對象的插槽拋出的異常呢?Qt:處理從後臺線程處理程序拋出的異常
IOW,如何重新實現後臺線程的notify()方法?
當您使用overriden notify方法創建自定義應用程序時;您創建的QThread使用過這種覆蓋方法(主線程)一旦它已經開始了自己的事件循環
這實際上意味着,如果你的任何插槽連接到的QThread ::啓動信號;那麼這個槽在線程的事件循環之外執行,因此不在被覆蓋的通知方法中。
這裏是一個代碼示例,有助於理解發生什麼:
#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();
}
在Windows上運行此代碼示例,Qt的5.9 Qt Creator中給出了例子:
輸出:
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
和Microsoft Visual Studio Runtime Library彈出窗口:
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)
如果你把斷點;一旦可以實現:
對象01中拋出的QThread :: EXEC方法,下降調用堆棧,我們可以看到我們是在ApplicationWithExceptionCatchedInNotify ::通知
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 ::調用qobject_impl.h 101 0x54a82428
6 QMetaObject ::激活qobject.cpp 3754 0x54a70ee0
7 QMetaObject ::激活qobject.cpp 3629 0x54a707a8
8 QTimer ::超時moc_qtimer.cpp 202 0x54a8f739
9 QTimer :: timerEvent qtimer.cpp 257 0x54a8f79a
10的QObject ::事件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 ::事件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 ::運行qthread.cpp 583 0x546501c3
32 QThreadPrivate ::開始qthread_win.cpp 380 0x5465caed
33 BaseThreadInitThunk KERNEL32 0x7ffb9f5b8364 34 RtlUserThreadStart ntdll 0x7ffba1bb7091
Object o2拋出QThread :: start方法;的線程2事件循環
1 ThrowingObject :: doThrowOutsideNotify main.cpp中以外45 0x7ff666152ba6 2 QtPrivate :: FunctorCall,QtPrivate ::列表<>,空隙,空隙(__cdecl ThrowingObject :: *)(無效)__ptr64 > ::調用qobjectdefs_impl.h 136 0x7ff66615358c 3 QtPrivate :: FunctionPointer ::呼叫,空隙> qobjectdefs_impl.h 170 0x7ff666152ce7 4 QtPrivate :: QSlotObject,無效> :: IMPL qobject_impl.h 121 0x7ff66615363e 5 QtPrivate :: QSlotObjectBase: :call qobject_impl.h 101 0x54a82428
6 QMetaObject :: activate qobject.cpp 3754 0x54a70ee0
7 QMetaObject ::激活qobject.cpp 3629 0x54a707a8
8的QThread ::開始moc_qthread.cpp 160 0x54650149
9 QThreadPrivate ::開始qthread_win。CPP 377 0x5465cad6
10 BaseThreadInitThunk KERNEL32 0x7ffb9f5b8364 11 RtlUserThreadStart NTDLL 0x7ffba1bb7091
可能超載Exec和放一試(){QThread的:: EXEC()}趕上(...){} – drescherjm
@drescherjm你的意思是拋出異常從插槽將「飛出」exec()方法?它似乎不適合我。 – ScumCoder
是的,我希望工作。抱歉。我對此沒有想法,但訂閱了。 – drescherjm