2015-01-21 3 views
2

Я запускаю приложение qml с плагином C++. Применение довольно просто:Каков правильный способ перехвата исключения метода, выполняющегося в другом потоке?

QApplication app(argc, argv); 
QQmlApplicationEngine engine; 
engine.load(QUrl(QStringLiteral("qrc:///ui/views/mainwindow.qml"))); 

return app.exec(); 

Но в qml-плагине есть много кода. Чтобы избежать зависаний в qml, я помещаю объект в поток на moveToThread() и вызывая методы по QMetaObject::invokeMethod() асинхронно с использованием параметра Qt::QueuedConnection. Проблема заключается в том, что методы, которые я называю по invokeMethod может бросить исключение (ы), а затем программа даст сбой, потому что я не могу их поймать:

try { 
    QMetaObject::invokeMethod(&qlNetwork, "disconnect", Qt::QueuedConnection); 
} catch (const std::runtime_error& e) { 
    emit error(e.what()); 
} 

Конечно, этот код не будет работать, так как вызов не- блокировка. Возникает вопрос: как же я могу перехватывать исключения из объекта в другом потоке (QThread)?

ответ

2

Вы должны создать слот для обертки, который вызывает disconnect из другого потока и обрабатывает исключение.

void ThisClass::wrapperMethod() { 
    try { 
     qlNetwork->disconnect(); 
    } catch (const std::runtime_error& e) { 
     emit error(e.what()); 
    } 
} 

И тогда вы вызываете метод обертку асинхронно:

QMetaObject::invokeMethod(this, "wrapperMethod", Qt::QueuedConnection); 

Убедитесь, что wrapperMethod является SLOT или она определяется как Q_INVOKABLE и ThisClass экземпляр перемещается в другой поток.


Возможное решение с использованием лямбды

QTimer *t = new QTimer(); 
connect(t, &QTimer::timeout, this, [=]() { 
    t->deleteLater(); 
    try { 
     qlNetwork->disconnect(); 
    } catch (const std::runtime_error& e) { 
     emit this->error(e.what()); 
    } 
}, Qt::QueuedConnection); 
/* don't forget to move the timer to the thread where 
    you want the lambda to be executed*/ 
t->moveToThread(targetThread); 
t->setSingleShot(true); 
t->start(0); 

Решение с использованием лямбды с QtConcurrent (Victor Полевого)

void ThisClass::performDisconnect() { 
    QtConcurrent::run([this]() { 
     try { 
      this->qlNetwork.disconnect(); 
     } catch (const std::runtime_error& e) { 
      emit error(e.what()); 
     } 
    }); 
} 
+0

Да, я думал об этом, но не здесь универсальное решение для такого обычного дело? –

+0

Что вы подразумеваете под универсальным решением? Исключения должны обрабатываться синхронно в том же потоке, что и вызов метода. – alediaferia

+0

Я имею в виду решение, которое может сделать это без каких-либо оберток. Например, некоторая внутренняя оболочка 'qt'' QThread :: run', которая ловит '(...)' и испускает какой-то сигнал или что-то в этом роде. –

Смежные вопросы