Delay closing the application in destructor waiting for a signal
-
Is it possible to delay (possibly with a timeout) the closing of a console application inside a destructor?
I have a class that needs to do some stuff (let's say an HTTP GET request or any other asynchronous call) when the application shuts down. It's easy to implement if you press the EXIT button... but I want to execute the procedure even in case of a SIGINT, SIGTERM, etc...
Hence I wrote a simple function to catch those signals and I connected them to the QCoreApplication::quit slot. In this way the destructors of my classes are called before the application is shut down.
In the destructor I fire the asynchronous call:
MyClass::~MyClass() { // fire asynchronous call _myOtherClass->shutdownCall(); // ? wait for a signal ? }
But what if I want to wait for a signal before closing the application?
// slot called when the related signal is emitted in shutdownCall() void MyClass::myOtherClassReply() { // ok, answer received, we can shut down }
-
Is it possible to delay (possibly with a timeout) the closing of a console application inside a destructor?
I have a class that needs to do some stuff (let's say an HTTP GET request or any other asynchronous call) when the application shuts down. It's easy to implement if you press the EXIT button... but I want to execute the procedure even in case of a SIGINT, SIGTERM, etc...
Hence I wrote a simple function to catch those signals and I connected them to the QCoreApplication::quit slot. In this way the destructors of my classes are called before the application is shut down.
In the destructor I fire the asynchronous call:
MyClass::~MyClass() { // fire asynchronous call _myOtherClass->shutdownCall(); // ? wait for a signal ? }
But what if I want to wait for a signal before closing the application?
// slot called when the related signal is emitted in shutdownCall() void MyClass::myOtherClassReply() { // ok, answer received, we can shut down }
-
@Mark81
The normal way to do a blocking wait for a signal to be emitted is via QEventLoop::exec().Whether it is safe/a good idea to do this in your class destructor depends on context.
-
@JonB what information I need to evaluate in order to decide whether the context is safe enough?
-
@JonB ok, so I change my question. What document should I read in order to learn how to achieve my goal?
@Mark81
I don't know so I will leave someone else to comment.
You might try it to see if it works or is a no-go from the outset.
Normally shutdown is done in response to QCoreApplication::aboutToQuit() signal.
I don't know whether there is an issue/how safe it is to do from your destructor.
You must also be careful how you handleSIGINT
/SIGTERM
signals safely from a Qt application. -
If connecting to a signal is not an option, the next thing that comes to mind is the destructor of a class that is deleted on the applications way out. A scope guard is practically the same, just that you can place it anywhere you want.
If things can go wrong, it might be worth gambling with a custom message logger to intercept fatal messages. And if things can go terribly wrong but cleanup is needed in a safe environment, you can always write a second application as a watch dog. It can be dormant and occasionally check the main application for recent signs of life. If a critical state is diagnosed, it will send the fire fighters.
-
already touch upon, but the brute force methods will be trapping signals and implementing an atexit() handler...but keep in mind that your cleanup may fail if the requisite objects have already been destroyed by the time the handlers are called.
-
Is it possible to delay (possibly with a timeout) the closing of a console application inside a destructor?
I have a class that needs to do some stuff (let's say an HTTP GET request or any other asynchronous call) when the application shuts down. It's easy to implement if you press the EXIT button... but I want to execute the procedure even in case of a SIGINT, SIGTERM, etc...
Hence I wrote a simple function to catch those signals and I connected them to the QCoreApplication::quit slot. In this way the destructors of my classes are called before the application is shut down.
In the destructor I fire the asynchronous call:
MyClass::~MyClass() { // fire asynchronous call _myOtherClass->shutdownCall(); // ? wait for a signal ? }
But what if I want to wait for a signal before closing the application?
// slot called when the related signal is emitted in shutdownCall() void MyClass::myOtherClassReply() { // ok, answer received, we can shut down }
@Mark81 said in Delay closing the application in destructor waiting for a signal:
Hence I wrote a simple function to catch those signals and I connected them to the QCoreApplication::quit slot.
One observation. I think you are saying you catch Linux signals like
SIGINT
/SIGTERM
and either callQCoreApplication::quit()
slot directly or maybe emit a signal which has this connected as a slot? What you are allowed to do from a Linux signal handler is very limited. The most I would do is emit a signal and theconnect()
must beQt::QueuedConnection
. I'm not even certain that is safe, but certainly better than anything which invokesQCoreApplication::quit()
directly. Let us know if you want us to dig out some code reference about what is safe to do from a Linux signal in a Qt application. -
@Mark81 said in Delay closing the application in destructor waiting for a signal:
Hence I wrote a simple function to catch those signals and I connected them to the QCoreApplication::quit slot.
One observation. I think you are saying you catch Linux signals like
SIGINT
/SIGTERM
and either callQCoreApplication::quit()
slot directly or maybe emit a signal which has this connected as a slot? What you are allowed to do from a Linux signal handler is very limited. The most I would do is emit a signal and theconnect()
must beQt::QueuedConnection
. I'm not even certain that is safe, but certainly better than anything which invokesQCoreApplication::quit()
directly. Let us know if you want us to dig out some code reference about what is safe to do from a Linux signal in a Qt application.@JonB yep, currently I'm doing this in main.cpp:
QObject::connect(&handler, &SignalsHandler::quit, &a, QCoreApplication::quit);
Actually, what do you mean when talking about "safe"?
Before kindly asking you to spend other time, I'm going to better understand what I have to do in order to close the connection with the remote device. Perhaps, there is a better way that does not require this "mess".Thanks for your availability
-
@JonB yep, currently I'm doing this in main.cpp:
QObject::connect(&handler, &SignalsHandler::quit, &a, QCoreApplication::quit);
Actually, what do you mean when talking about "safe"?
Before kindly asking you to spend other time, I'm going to better understand what I have to do in order to close the connection with the remote device. Perhaps, there is a better way that does not require this "mess".Thanks for your availability
@Mark81
While inside a Linux signal handler, such as fromSIGINT
/SIGTERM
, you are very limited as to what you are allowed to do "safely". Basically you are in a context where you are supposed to do as little as possible (e.g. set a variable) and then exit the signal handler. You are not supposed to do anything at all "complicated". So, for example, using Qt I think it would be best to post a simple message/signal --- assuming that is safe --- and exit the signal handler, allowing the event loop to later pick that up and do the actual exiting, rather than doing the exit from within the signal handler directly.In your
connect()
above, for example, I would be making it aQt::QueuedConnection
. (For other reasons the code at https://doc.qt.io/qt-6/qcoreapplication.html#quit actually recommends/shows this anyway.)