I need to detect the application get exit as normal or crash. QProcess have the finished() signal and can get the exit code. But i need this exit code for QApplication when the application get crash or close.
When your process crashes, it's gone. The crash means that the process has finished because of an unhandled exception. Your job should be to prevent the crash from happening. In other words: handle the exceptions. Note that the exceptions may not be C++ exceptions, they may be low-level platform-specific mechanisms, such as native exceptions on Windows or signals on UNIX. You'd have to handle those, but recognize that the underlying issue is not fixed merely because you catch such an exception. You must assume that the state of your application has been corrupted, and the only safe thing to do is to exit ASAP anyway. For example, do not try to modify any files: you're likely to corrupt them.
I don't think this is something you can do just like that. Reading the value returned by QApplication::exec() is related to the Qt infrastructure:
Enters the main event loop and waits until exit() is called, then
returns the value that was set to exit() (which is 0 if exit() is
called via quit()).
Usually your main looks like this:
#include <QApplication>
int main( int argc, char **argv )
{
QApplication a( argc, argv );
// Initialize your widget(s)
return a.exec(); // You can store this and check its value
}
However if I'm not mistaken this doesn't include handling a crash of your application (segmentation fault, unhandled exception etc.). In Linux people usually use a script which starts the application and then reads its exit code after the application quits or crashes. If you use Linux you can use echo $? to read the exit code from the bash scrip (or its equivalent for a different shell) and then do something based on its value.
Note also that you can at least do some exception handling since some crashes result in exactly that - an exception that has been thrown for some reason and has not been processed properly. Unhandled exceptions in Qt get propagated to the top level (that is QCoreApplication).
Related
For example:
void MainWidget::testThreadTask()
{
qDebug() << "On test task";
}
void MainWidget::onBtnClick()
{
QThread *thread = new QThread;
connect(thread, QThread::started, this, testThreadTask);
thread->start();
qDebug() << "Thread START, now we wait 5s";
QElapsedTimer timer;
timer.start();
while (timer.elapsed() < 5000)
{
}
qDebug() << "END";
}
The program output is:
START wait 5s
END
On test task
I want to create a task to handle something after the button is pressed, and then the function will wait for the task to complete before returning.
In fact, it may not be necessary to create a new task and wait for it to execute, because since you have to wait and get stuck there, why not run it directly in the function.
But this is actually a problem when I deal with QT serial data. I want to send the data to the serial port after pressing the button, and then wait for the data (by constantly reading), but I find that when I have been waiting, the serial port can not read the data at all, only when I exit the function the serial port can read the data.
Is there any way to deal with serial data sending and receiving synchronization?
void MainWidget::onBtnClick()
{
serial->write("Test");
if (serial->bytesAvailable())
{
QByteArray data = serialIo->readAll();
// handle the data
}
}
You are mistaken with what is happening in your application. I suggest you read Threads and QObjects (the entire page), Qt::ConnectionType and the detailed description of QThread.
What is happening to you is:
MainWidget does not live in thread. For the slot of a regular object to be called from thread, it first needs to be moved to that thread.Note that subclasses of QWidget cannot be moved to another thread. Because some OS supported by Qt limit where windows can live, they made the choice to force all QWidget to stay in the main thread, in all OS Qt can execute on.
When you connect thread to this (which BTW is incorrect in your question, it should have been with ampersands connect(thread, &QThread::started, this, &MainWidget::testThreadTask);), you create a queued connection, even though the thread has not technically started yet.
When you start the thread:
It fires its started signal.
Because the connection is a Qt::QueuedConnection, the slot will only be executed after returning to the main thread's event loop, i.e. some time after returning from onBtnClick.
Notes:
You would have more useful information in qDebug() about the threads running your code by using QThread::currentThread().Even better than that, your IDE should provide you a window specifically to see what thread has reached a breakpoint (Ctrl+Alt+H on Visual Studio).
At the risk of insisting, keep in mind this warning from the Qt help:
Be aware that using direct connections when the sender and receiver live in different threads is unsafe if an event loop is running in the receiver's thread, for the same reason that calling any function on an object living in another thread is unsafe.
With that said, because you wait 5 seconds before returning to the event loop and because it is only test code (= there should be no bug + it does not matter even if there is one), you should try to create a Qt::DirectConnection, just to see the slot be invoked from the worker thread.
The detailed description of QThread (link above) shows a complete working example of a worker object being moved to the new thread before it is started. The point is:
A worker object is created, then moved to the worker thread.
Connections are created for the controller to send QString to the worker object via signal/slot and for the worker object to return result to the controller via signal/slot too.
All these connections are Qt::QueuedConnection by default since the worker object was moved.
The worker thread is started. Since run was not overriden, it starts an event loop (in exec).
And there you have it.
Remember 1 things: widgets cannot be moved!!! Create your own worker object.
I make some https requests directly from my qml views, for instance for image sources. As I have a self signed certificate server side, I need to tell qt to ignore some ssl errors (I control both the server and the client applications, so this shouldn't really be a problem).
I've made a QQmlNetworkAccessManagerFactory to create NAMs, where I connect to the sslErrors signal.
UltraQmlAccessManagerFactory.h:
#ifndef FACKFACKTORy_H
#define FACKFACKTORy_H
#include <QQmlNetworkAccessManagerFactory>
#include <QObject>
#include <QNetworkReply>
#include <QList>
#include <QSslError>
#include <QNetworkAccessManager>
#include <QDebug>
#include <QSslCertificate>
class UltraQmlNetworkAccessManagerFactory : public QObject,
public QQmlNetworkAccessManagerFactory {
Q_OBJECT
private:
QNetworkAccessManager* nam;
QList<QSslError> expectedSslErrors;
public:
explicit UltraQmlNetworkAccessManagerFactory();
~UltraQmlNetworkAccessManagerFactory();
virtual QNetworkAccessManager* create(QObject* parent);
public slots:
void onIgnoreSslErrors(QNetworkReply* reply, QList<QSslError> errors);
};
#endif
UltraQmlNetworkAccessManagerFactory.cpp:
#include "UltraQmlNetworkAccessManagerFactory.h"
UltraQmlNetworkAccessManagerFactory::UltraQmlNetworkAccessManagerFactory() {
}
UltraQmlNetworkAccessManagerFactory::~UltraQmlNetworkAccessManagerFactory() {
delete nam;
}
QNetworkAccessManager* UltraQmlNetworkAccessManagerFactory::create(QObject* parent) {
QNetworkAccessManager* nam = new QNetworkAccessManager(parent);
QObject::connect(nam, SIGNAL(sslErrors(QNetworkReply*, QList<QSslError>)),
this, SLOT(onIgnoreSslErrors(QNetworkReply*,QList<QSslError>))
);
return nam;
}
void UltraQmlNetworkAccessManagerFactory::onIgnoreSslErrors(QNetworkReply *reply, QList<QSslError> errors) {
for (int i = 0; i < errors.size(); i++) {
qDebug() << "e: " << errors.at(i) << endl;
}
reply->ignoreSslErrors(errors);
}
There is also some glue in main.cpp that sets this factory to be used, I doubt that part is a source of errors as the qDebug prints are visible in the output.
As can be seen in the .cpp file in the function/slot onIgnoreSslErrors, I try to ignore every error (as a test) that I receive, but in the output I do not get the expected results.
Output
e: "The certificate is self-signed, and untrusted"
qrc:/qml/file/ImageView.qml:16:5: QML Image: SSL handshake failed
I have successfully made QNetworkRequests from C++ directly with a QSslConfiguration, specifying TLSV1_0 and a certificate. As I have a suspicion that the handshake fails because one side expects SSL and the other TLS I have also tried to set the QSslConfiguration on the QNetworkRequest object throgh reply->request(); This, however, changes nothing.
(This is a very old one but as I stumbled over this recently and haven't found the answer, I think it's still worth answering)
You don't show the place where you actually setup the factory object but it is extremely likely that it does not belong to the same (actually, any) thread used when its create() method is called. Here's an excerpt from the Qt documentation on the class:
the developer should be careful if the signals of the object to be returned from create() are connected to the slots of an object that may be created in a different thread
It further mentions authenticationRequired() signal but sslErrors() acts in the same way: both signals, among a few others, need either a direct or a blocking queued connection so that by the time of returning to the place of emitting the signal the network reply object has already been configured by the slot.
What happens in your case is (very likely) the following (TL;DR: your slot is called asynchronously by a queued connection because it lives in a different thread, while sslErrors() requires a synchronous change to the running network reply object; despite the order of log lines, the request fails first and ignoreSslErrors() is called later):
The factory object is created, and the QML engine configured, in the main thread.
QML engine spawns a few threads to perform backend stuff, notably network requests for URLs (I'm making the assumption here that your ImageView.qml has an Image component). To perform the network request, these threads call UltraQmlNetworkAccessManagerFactory::create().
create() produces a NAM object and sets up a connection on it. The parent here is either the QQmlEngine object or (specifically for image requests) the backend thread object, as you can see e.g. here. Therefore, this NAM object belongs to the backend thread.
connect() uses Qt::AutoConnection type by default, which, since the threads of the factory and of the NAM object are different, corresponds to Qt::QueuedConnection. As a sidenote, the threads are checked at the time of signal invocation.
Eventually a QNetworkAccessManager::sslErrors() signal is emitted. Since this is a queued connection, the only thing that immediately happens is placing an invocation of onIgnoreSslErrors() on the event queue for the main thread.
If you're very lucky, you may have a context switch to the main thread right after that - but there's literally nothing to ensure that so it's much more likely that control returns to the site where QNetworkAccessManager::sslErrors() was emitted. And since ignoreSslErrors() wasn't called, the request fails the handshake. The backend thread posts relevant data from the (failed) QNetworkReply object back to the main thread - see the postReply call in the middle of the method (or it may do it a bit later - that doesn't matter anymore).
Once the context switches to the main thread ignoreSslErrors() is executed - alas, it's already too late, as the network reply has very likely finished with failure already; but that first log line comes out now.
The main thread goes on through the event loop and finds the QQuickPixmapReply::Event object with the failure data. After some unroll of the calls and signals the failed image ends up in QQuickImageBase::requestFinished() that prints the second log line for you .
As for the fix, it's tempting to just specify Qt::BlockingQueuedConnection as the fifth parameter to connect(). Unfortunately, this will deadlock if a request is ever made from QQmlEngine that runs in the main thread - and uses a NAM instance created by this factory to, e.g., request QML components over the network. Best I could come out with so far is an equivalent of
connect(nam, SIGNAL(sslErrors(QNetworkReply*, QList<QSslError>)),
this, SLOT(onIgnoreSslErrors(QNetworkReply*,QList<QSslError>)),
currentThread() == this->thread() ? Qt::DirectConnection
: Qt::BlockingQueuedConnection
);
I am developing an application on Qt symbian, in which I have to restart my application within my application, have used:
qApp->quit();
QProcess::startDetached(qApp->arguments()[0],qApp->arguments());
from a method in mainWindow. It is working fine on simulator but not on device, it closes but not restarting by itself, I have to restart it by myself, is there anything else I have to do to make it work on device.
One solution would be to create small console process that you can launch from your main program before closing it. Then this console process would just launch your program and close.
I have been using this kind of processes to keep track of my apps and restart them when they crash.
One minor but fundamental thing: on Symbian there is an emulator and not a simulator. The difference is that the later simulates the device on the assembly level while the former does it only on API support level. For example iPhone simulator simulates the phone on assembly level. Contrarily in Symbian the underlying API implementation might be and is completely different for the ARM and for the WINS architecture. Especially in such cases when you interact with the OS like exiting the application.
The application quit operation on Symbian is eventually implemented by throwing a special exception (I don't remember it's name, something like KExitException) that is caught by the main Active Scheduler loop that tells the kernel to shut down the process. In other words it means that it is a synchronous call. If you first call quit then startProcess then the later will be never executed. It is not that clear why does not it work if you first call startProcess and then quit: this might be an asynchronous call that can not complete before you exit, or you simple can not start the same (GUI) application in two instances. Anyway check the return value of startProcess to see whether it succeeded or not.
Your ultimate solution will be to create a watchdog process as #Riho suggested. You start the watchdog process before you call quit, in the watchdog main function you wait some seconds and restart your application. You will need SwEvent capability for your watchdog.
I have tried it with Qprocess() and it seems to be working fine (still testing for memory and thread issues)
in main.cpp I write this code (which I got from other link )
int main(int argc, char *argv[])
{
#define RESTART_CODE 1000
int return_from_event_loop_code;
QPointer<QApplication> app;
QPointer<MainWindow> main_window;
do
{
if(main_window) delete main_window;
if(app) delete app;
app = new QApplication(argc, argv);
main_window = new MainWindow;
QList<QString> lang = AppStatus::getCurrentLanguage();
QTranslator translator;
translator.load(lang.at(0));
app->installTranslator(&translator);
main_window->setOrientation(MainWindow::ScreenOrientationLockPortrait);
#if defined(Q_OS_SYMBIAN)
main_window->showMaximized();
#else
main_window->show();
#endif
return_from_event_loop_code = app->exec();
}
while(return_from_event_loop_code==RESTART_CODE);
return return_from_event_loop_code;
}
and in my method from where I have to restart my app I have written this.
QProcess::startDetached(qApp->applicationFilePath(),qApp->arguments());
qApp->exit(RESTART_CODE);
And my app is restarting like I wanted.. If any changes nedded plese let me know.
I have a Qt application that runs on a linux machine that displays UI windows on a Windows machine running an X server. There's a strong possibility that the users of my application will logout of Windows or kill the X server without quitting my application first.
Is there a way to handle the unexpected shutdown of the X server, so that the application can gracefully shutdown, save stored data, etc? So far I've tried tying QApplication's aboutToQuit signal to a slot in my app, plus catching all exceptions in main. Neither worked as I expected.
I think your best bet is to attempt to handle it via signal handling
depending on how application is being killed by the OS, exiting gracefully may or may not be possible at all.
I'm not sure, but maybe this QCoreApplication::aboutToQuit() signal can help you.
If connection with the X server is lost then libX11 inside the application calls _XIOError() function that calls _XDefaultError handler that calls exit(). It is possible to override that with a custom handler:
#include <X11/Xlib.h>
static int handler(Display *dpy)
{
/*
* cleanup
* ...
*/
exit(1);
return 0;
}
...
int main(int argc, char** argv)
{
QApplication app(argc, argv);
XSetIOErrorHandler(handler);
...
It's better to still call exit() in the handler because Qt will segfault anyway without a proper X connection.
I am having an application heavily based on QT and on a lot of third party libs. These happen to throw some exceptions in several cases.
In a native Qt App this causes the application to abort or terminate. Often the main data model is still intact as I am keeping it in pure Qt with no external data.
So I am thinking that I could also just recover by telling the user that there has occurred an error in this an that process and he should save now or even decide to continue working on the main model.
Currently the program just silently exits without even telling a story.
Sometimes it's really hard to catch all exception. If one exception accidently slips through, the following helps a lot. Inherit from QApplication and override the notify() function in the following way
bool MyApplication::notify(
QObject * receiver,
QEvent * event )
{
try
{
return QApplication::notify(receiver, event);
}
catch(...)
{
assert( !"Oops. Forgot to catch exception?" );
// may be handle exception here ...
}
return false;
}
Then replace the QApplication in your main() function by your custom class. All events and slots are issued through this function, so that all exceptions can be caught and your application becomes stable.
As stated in the Qt documentation here, Qt is currently not fully exception safe. The "Recovering from exceptions" section on that page describes the only thing which you can do in a Qt application when an exception is thrown - clean up and exit the app.
Given that you are using third party libraries which do throw exceptions, you need to catch these at the boundary between the external library and the Qt code, and handle them there - as stated in Caleb's comment. If the error must be propagated into the Qt application, this must be done either by returning an error code (if possible), or by posting an event.