2014-06-17 125 views
2

我知道您需要重新实现QApplication :: notify()方法来正确捕获从主线程的事件处理程序抛出的异常。 但其他线程呢?比方说,我有一个插槽的对象,并且此对象位于QThread中(使用默认的run()方法,该方法只调用exec()),即该对象的线程关联性是背景QThread。那么,我应该在哪里捕获从该对象的插槽抛出的异常呢?Qt:处理从后台线程处理程序抛出的异常

IOW,如何重新实现后台线程的notify()方法?

+0

可能超载Exec和放一试(){QThread的:: EXEC()}赶上(...){} – drescherjm

+0

@drescherjm你的意思是抛出异常从插槽将“飞出”exec()方法?它似乎不适合我。 – ScumCoder

+0

是的,我希望工作。抱歉。我对此没有想法,但订阅了。 – drescherjm

回答

0

当您使用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