PDA

View Full Version : QProcess disconnect trouble



wally
4th April 2010, 16:07
Hello,

I'm creating a simple watchdog program that watches a process. If the process exits or crashes I want to restart the process. My dialog has a program exe and working directory line edits, for program selection, along with Start/Stop/Restart buttons. It has a QTimer for automatically restarting a crashed/exited program after N seconds.

My program functions as a systray icon that provides message bubbles based on the status or any crash/exit events. So I have the QProcess signals connected like this in my dialog's constructor:

process = new QProcess();
connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(handleProcessError(QProcess::ProcessError)));
connect(process, SIGNAL(finished(int, QProcess::ExitStatus )), this, SLOT(handleProcessFinish(int, QProcess::ExitStatus)));

When pushing the stop button, I want to kill the process with QProcess::kill(). When the process is killed, naturally, the handleProcessError slot gets called and I do not want this. I wanted to disable this by using:

disconnect(process, SIGNAL(error(QProcess::ProcessError)), 0, 0);
disconnect(process, SIGNAL(finished(int exitCode, QProcess::ExitStatus exitStatus)), 0,0);
process->kill();

I've also tried calling:

process->disconnect();
process->kill();
in an attempt to blindly disconnect everything.

It appears after calling these disconnect calls the error signal is not actually disconnected as I still get my message bubble popping up telling me that the program has crashed. Furthermore, my handleProcessError slot is designed to call my restart QTimer::start() so that the program will automatically restart.

My hopes to disconnect it have failed and when the user clicks "Stop" I do not want the program to automatically restart. This has led me to deleting the QProcess object, and creating a new instance.

Any ideas as to why the signals are not getting disconnected?

Using Qt 4.5.1 with VS2008

Thanks,
Darryl

squidge
4th April 2010, 18:10
process->kill is provided as a absolutely last resort to try and kill a process that isn't responding. You shouldn't use it for normal operations. When the user presses 'Stop', send a signal to the process to quit normally, and then you will not get an error signal.

wally
5th April 2010, 02:35
Thanks for the tip, I will try that out instead of using process->kill().

That still does not, however, address the issue with the signals not being disconnected.

Any ideas?

borisbn
5th April 2010, 04:24
You can't write formal parameters in SIGNAL macro neither in connect nor in dosconnect. See program output in 'Output' window in Studio. Wrong calling of connect/disconnect writes there a message

wally
5th April 2010, 15:52
process->kill is provided as a absolutely last resort to try and kill a process that isn't responding. You shouldn't use it for normal operations. When the user presses 'Stop', send a signal to the process to quit normally, and then you will not get an error signal.

Actually, the documentation for QProcess::terminate() says that the "Console applications on Windows that do not run an event loop, or whose event loop does not handle the WM_CLOSE message, can only be terminated by calling kill()."

So I would need to call kill to ensure that any application that is run by the WatchDog is terminated, on Windows at least.

wally
5th April 2010, 16:12
You can't write formal parameters in SIGNAL macro neither in connect nor in dosconnect. See program output in 'Output' window in Studio. Wrong calling of connect/disconnect writes there a message

I haven't seen any problems in the output. I'm also not sure what you mean by formal parameters. Do you mean defining the variable name in the function like:
SIGNAL(error(QProcess::ProcessError error)) I know that this will not work and the signals I have defined do not define the value "error" I know that the SIGNALS are connected as they will enter the slot. I corrected this error from my first post.

Either way, calling process->disconnect() should disconnect all the sender object and all signals from all receiver objects and slots.

I've even tried calling
process->blockSignals(true);
process->kill();
process->blockSignals(false);
and my slots still get entered.

Any one have any other ideas as to why my signals are not getting disconnected?

wally
5th April 2010, 16:18
I think QtCentre's moving to a new host may have ruined the code tags in my initial post. So that everyone is clear:
I've connected my signals to my process in the Dialog's constructor like this (and I have verified that they are connected):

process = new QProcess();
connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(handleProcessError(QProcess::ProcessError)));
connect(process, SIGNAL(finished(int, QProcess::ExitStatus )), this, SLOT(handleProcessFinish(int, QProcess::ExitStatus)));

When pushing the stop button, I want to kill the process with QProcess::kill(). When the process is killed, naturally, the handleProcessError slot gets called and I do not want this. I wanted to disable this by using:

disconnect(process, SIGNAL(error(QProcess::ProcessError)), 0, 0);
disconnect(process, SIGNAL(finished(int exitCode, QProcess::ExitStatus)), 0,0);
process->kill();

I've also tried calling:

process->disconnect();
process->kill();
in an attempt to blindly disconnect everything.

the slots, handleProcessError and handleProcessFinish are still being called.

squidge
5th April 2010, 18:19
Actually, the documentation for QProcess::terminate() says that the "Console applications on Windows that do not run an event loop, or whose event loop does not handle the WM_CLOSE message, can only be terminated by calling kill()."It depends on what your process does. If it has a systray icon, then it must have an event loop.

wally
5th April 2010, 18:24
It depends on what your process does. If it has a systray icon, then it must have an event loop.

Understandable. But the QProcess that is running is not necessarily in the Systray. The program that calls the QProcess runs in the systray.

Eitherway, the signals on the QProcess do not get disconnected. I tested connecting/disconnecting signals from other random objects (like a spinbox) and that works fine.

I'm starting to think that the signals of a QProcess that has an active process cannot be disconnected while the process is still running.

squidge
5th April 2010, 19:48
Have you tried blockSignals ?

wally
5th April 2010, 20:24
Yup. See post #6 (http://www.qtcentre.org/threads/29556-QProcess-disconnect-trouble?p=138807#post138807)

Didn't work either.

norobro
6th April 2010, 01:22
Maybe it's a windows/vs problem. You might try your app on Linux or do somethiing simple like the following to see if it works:

I created a new GUI project with Qt Creator. Used your code in the MainWindow constructor to start a process (a php script that waits for input on stdin) and make connections, put a push button in the form, and created two slots:
void MainWindow::on_pushButton_clicked(){
disconnect(process,SIGNAL(error(QProcess::ProcessE rror)),0,0);
process->kill();
}

void MainWindow::handleProcessError(QProcess::ProcessEr ror){
qDebug() << process->errorString();
}
It silently kills the process as shown. If I comment out the disconnect statement I get "Process crashed".

wally
6th April 2010, 02:48
Maybe it's a windows/vs problem. You might try your app on Linux or do somethiing simple like the following to see if it works:

I created a new GUI project with Qt Creator. Used your code in the MainWindow constructor to start a process (a php script that waits for input on stdin) and make connections, put a push button in the form, and created two slots:
void MainWindow::on_pushButton_clicked(){
disconnect(process,SIGNAL(error(QProcess::ProcessE rror)),0,0);
process->kill();
}

void MainWindow::handleProcessError(QProcess::ProcessEr ror){
qDebug() << process->errorString();
}
It silently kills the process as shown. If I comment out the disconnect statement I get "Process crashed".

Hmmm.. Maybe it is a Windows problem since that's essentially what I tried.

What version of Qt are you using?

I will try this in Linux and/or QtCreator tomorrow.

ChrisW67
6th April 2010, 03:07
From post 7:


disconnect(process, SIGNAL(error(QProcess::ProcessError)), 0, 0);
disconnect(process, SIGNAL(finished(int exitCode, QProcess::ExitStatus)), 0,0);
process->kill();

should not list the name of the int parameter at line 2. Perhaps this leaves the finished() signal still connected?

Have you tried calling QProcess::terminate() (close gracefully) rather than QProcess::kill() (close with mallet)? I cannot imagine many Windows applications that ignore the WM_CLOSE message sent by terminate()

norobro
6th April 2010, 04:15
@wally - I'm using Qt 4.6.0 on Linux.

I recently installed Qt 4.6.2 on my WinXP partiton and thought I'd give my simple app a try. I started "calc.exe" as a process and it ended silently. So disconnect worked here. Also it ended whether I used the "mallet" (TM ChrisW67) or terminate() .

norobro
6th April 2010, 04:53
should not list the name of the int parameter at line 2. Perhaps this leaves the finished() signal still connected?I missed that. I guess that is what borisbn is alluding to in post #4.
I put that slot in my app with the disconnect error and received a "no such slot" warning on the command line but the process still terminated without complaining.

squidge
6th April 2010, 08:07
Yup. See post #6 (http://www.qtcentre.org/threads/29556-QProcess-disconnect-trouble?p=138807#post138807)

Didn't work either.In post #6, you re-enable directly after the kill. I was thinking of leaving the blocking active until the process is restarted, just in case some signals are in the event queue.

wally
6th April 2010, 13:10
In post #6, you re-enable directly after the kill. I was thinking of leaving the blocking active until the process is restarted, just in case some signals are in the event queue.

Good point. I'll give that a shot.

wally
6th April 2010, 13:14
From post 7:


disconnect(process, SIGNAL(error(QProcess::ProcessError)), 0, 0);
disconnect(process, SIGNAL(finished(int exitCode, QProcess::ExitStatus)), 0,0);
process->kill();

should not list the name of the int parameter at line 2. Perhaps this leaves the finished() signal still connected?

Have you tried calling QProcess::terminate() (close gracefully) rather than QProcess::kill() (close with mallet)? I cannot imagine many Windows applications that ignore the WM_CLOSE message sent by terminate()

Sorry that's a typo.. I don't have the name of the int parameter in my actual code.

Regarding QProcess::terminate() vs. QProcess::kill(), the documentation says that "Console applications on Windows that do not run an event loop, or whose event loop does not handle the WM_CLOSE message, can only be terminated by calling kill()." Since, I'm using this program to run any possible program (including console applications) I will have to stick with the "mallet."

wally
6th April 2010, 15:48
Hello Everyone,

Thank you for your help. The solution was my lack of awareness on what's happening when you call QProcess::kill(). I was trying to disconnect and then reconnect my signals by calling the connect immediately after calling kill() (like in post #6 (http://www.qtcentre.org/threads/29556-QProcess-disconnect-trouble?p=138807#post138807) where I call blockSignals before and after the kill call.

I got the idea from fatjuicymole when he made a comment about my post #6. The process object was getting its signals reconnected before the external program had been terminated, since QProcess::kill() is not a synchronous function as it does not wait for the external function to be terminated.

Now when I press the stop button, the slot stopProcess contains the following:

disconnect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(handleProcessError(QProcess::ProcessError error)));
disconnect(process, SIGNAL(finished(int, QProcess::ExitStatus )), this, SLOT(handleProcessFinish(int, QProcess::ExitStatus)));
process->kill()

and then when I press the start button I reconnect the signals, e.g.:

connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(handleProcessError(QProcess::ProcessError error)));
connect(process, SIGNAL(finished(int, QProcess::ExitStatus )), this, SLOT(handleProcessFinish(int, QProcess::ExitStatus)));
process->start(processName);

Thanks for your help everyone. The problem, like usual, ended up being the user. You learn something new everyday, even though you realize that you should've known it anyways :)

squidge
6th April 2010, 17:19
Regarding QProcess::terminate() vs. QProcess::kill(), the documentation says that "Console applications on Windows that do not run an event loop, or whose event loop does not handle the WM_CLOSE message, can only be terminated by calling kill()." Since, I'm using this program to run any possible program (including console applications) I will have to stick with the "mallet."A better idea might be to use QProcess::terminate(), and if the process doesn't terminate within some time frame, then use QProcess:kill(). At least then it'll give the process that amount of time to cleanup if necessary, and will also work in situations where the process doesn't handle WM_CLOSE.