My windows/QT application is not exiting consistently.
After the object clean up, I am trying to delete the QProcess object. But it's not cleaning up the process and it can be shown in the task manager.
delete process;
process = 0;
I think delete process is not working because some threads are running at the background. I want to ensure that all threads are closed gracefully, so the process will exit.
Please let me know the right way to do this.
The task manager does not show your QProcess object, and deleting that object will not affect the task manager. If there is still code running in your process, the process will continue to exist according to the OS.
If you really want to exit the process, you can call the Win32 function ExitProcess(). Just make sure you've saved everything you want to.
Qt will normally exit the process when all your threads stop running.
One problem may be that the QProcess object doesn't represent a child thread, it represents an independent process, you probably want to use the QThread object.
With the QThread object you can use some combination of the quit, exit, wait, and terminate depending on the exact content of you child thread, check the documentation for the differences.
Related
I'm making a render job manager for blender. I have a class that builds up a queue of render jobs and then you click Start and it begins rendering one at a time with a loop. My problem is that the waitForFinished() method holds up my entire program. But I've read that you shouldn't use QThread with QProcess.
This is how the loop works.
do{
if(myProcess->state() == QProcess::NotRunning) {
myProcess->setProgram(blenderPath);
myProcess->setArguments(arguments);
myProcess->start();
myProcess->waitForFinished(-1);
//Get rid of current rendering job to prepare for the next job
renderQueueList.pop_front();
}
}while(renderQueueList.empty() != true);
Can I use a separate thread to launch QProcess and what would be the best way to do this? I've read that you make an abstract of QThread or use signals and slots but it's so confusing, specially when I need to pass arguments to the process.
Thank you.
Edit:
I want to add that the process must finish before running a new process. It has to go in order. That's why I think I need the process to run in its own thread.
QProcess already executes in a different process, i.e. asynchronously with your application.
When you call waitForFinished() the application locks up until the process in QProcess finishes. You need to connect instead to the finished() and probably errorOccured() signals, and then your application will keep running while the QProcess runs in the background.
You'll need to change that loop to a check that the queue isn't empty and a new process start on the finished() signal.
If you run a QThread that runs QProcesses and does waitForFinished() you will free the main application thread indeed, but it's a pointless extra layer when QProcess is asynchronous already and you have have finished() to let you know when it's done without locking up a thread, be it the UI thread or a separate one.
In my Qt C++ program I created a process as follows:
myProcess = new QProcess();
myProcess->start(programpath, arguments);
Terminating the process is handled as follows:
myProcess->terminate();
Terminating the child process with QProcess::kill(),terminate() or close() works, but I don't want to use it because it doesn't give the child process a chance to clean up before exiting.
Is there any other way to exit the process? Thanks!
The polite way would be for the parent process to politely ask the child process to go away. Then when the child process exits (of its own volition), the QProcess object will emit a finished(int, QProcess::ExitStatus) signal, and you can have a slot connected to that signal that will continue your process (e.g. by deleting the QProcess object at that time). (Or if you don't mind blocking your Qt event loop for a little while, you could just call waitForFinished() on the QProcess object after asking it to exit, and waitForFinished() won't return until the process has gone away or the timeout period has elapsed)
Of course for the above to work you need some way to ask the child process to exit. How you go about doing that will depend on what the child process is running. If you're lucky, you are in control of the child process's code, in which case you can modify it to exit in response to some action of the parent process -- for example, you could code the child process to exit when its stdin descriptor is closed, and have the parent process call closeWriteChannel() on the QProcess object to cause that to happen. Or if you're running under Linux/Unix you could send a SIGINT signal to the child process and the child process could set up a handler that would catch the signal and start an orderly shutdown. Or if you want something really stupid-quick and dirty, have the child process periodically check for the presence of a file at a well-known location (e.g. "/tmp/hey-child-process-PIDNUMBERHERE-go-away.txt" or something) and the parent process would create such a file when it wants the child to go away. Not that I'd recommend that last method as I don't think it would be very robust, except maybe as a proof of concept.
terminate actually gives the process an chance to clean up. The program being terminated just has to take that chance i.e. the system sents a SIGTERM and the application and it can ignore that and exit cleanly on its own. If this is still not nice enough then you have to implement your own way of asking the application to quit. Jeremy Friesner made some good successions. If the application code is not written by yourself you'll have to read the documentation for that program closer, maybe its documented how to do that.
I'm using a List of QProcess objects to keep track of some processes that need to be start/stopped at user defined intervals.
I'm able to start and stop the processes OK. But the issue arises when I stop a process using the following methods (Pseudo code):
process->start("PathToProcess","Some Arguments");
//Do some stuff.
process->terminate();
However, if I try to start the process again at another time, I get the error:
QProcess::start: Process is already running
I can do a ps -ef|grep processName and find that it is indeed dead, but it's sitting in a defunct state which I think is preventing me from starting it again.
What do I need to do to prevent this defunct state, or remove the defunct method so I can start my process again without reconstruction?
Figured out what was causing the error.
In qprocess_unix.cpp, you'll find a class called QProcessManager. Essentially this class has signal handlers that watch for child processes that have died. When a child dies, the QProcessManager sends a message across a pipe that lets the QProcess class know that it terminated/died.
In a unrelated part of my code, I had set up some signal catching statements that I used for various puposes. However, these signal catches were catching my SIGCHLD event and thus the QProcessManager was never being triggered to pipe to the QProcess that it died.
In my case, my only options are to either watch for the death of the child manually or to remove the signal catching I'm performing in my other sections of code.
For future reference, if you have this problem, you may be better off doing POSIX calls for kills and terminates, and checking the return value of those calls manually. If success, perform a:
process->setProcessState(ProcessState::NotRunning);//Specify the process is no longer running
waitpid(process->pid(),NULL,WNOHANG); //Clear the defunct process.
Thanks all.
Call process->waitForFinished() after calling process->terminate() in order to reap the zombie process. Then you can reuse the process object.
I have a program which needs to invoke a process to perform an operation and wait for it to complete the operation. The problem is that the invoked process clones itself and exits, which causes the wait api to return when the process exits. How can I wait for the cloned process to finish execution and return?
I am using the windows JOB object as mentioned in http://www.microsoft.com/msj/0399/jobkernelobj/jobkernelobj.aspx, But I am not sure if this is the best way.
umm, I'm pretty sure you can can the spawner process id from any process. I'd iterate through all the processes, find the one's who's parent id matches the one of the process you spawned, and wait for it to die.
alternatively (I mean, thats pretty hack) what is the child child process doing? is there some other way you could detect when it has finished doing what it is meant to do?
a hack way to get a process's parent id
http://www.codeguru.com/cpp/w-p/win32/article.php/c1437
takes a handle, and using the method in the code above, returns the parent id.
http://msdn.microsoft.com/en-us/library/ms684280(VS.85).aspx
OpenProcess takes an id, gets a handle to it (if you're lucky)
http://msdn.microsoft.com/en-us/library/ms684320(VS.85).aspx
GetProcessId takes a handle, gets it's id.
http://msdn.microsoft.com/en-us/library/ms683215(VS.85).aspx
GetExitCodeProcess takes a handle, returns whether the process is done or not.
http://msdn.microsoft.com/en-us/library/ms683189(VS.85).aspx
so appart from using hidden nt calls that it expressly tells you not to, you would basically have to create your process, get it's id, then spam all the process, opening them and checking their parent ids against the id of the process you created, if you didn't find one, then it's done, if you do, spam it with GetExitCodeProcess until its done.
I haven't tested any of this, but it looks like A way to do it. though if it's THE BEST way to do it I might just have to loose all faith in windows...
+1 for using job objects ;)
Assuming the process that you're running isn't spawning the cloned version of itself in such a way that it breaks out of the job...
You should be able to simply monitor the job events and act on JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO (see JOBOBJECT_ASSOCIATE_COMPLETION_PORT and SetInformationJobObject()). Monitoring the job in this way will also give you notifications of the processId's of new processes created within the job and details of when they exit.
If you have control over the source of invoked process, one possible solution would be to make it wait for the process it spawns by cloning itself.
I will jump right in, to be brief and descriptive:
C++, Windows API
I am creating child processes using CreateProcess to run external (command-line) applications. I have built in a time-out, and if the child process has not returned normal execution by that time, I wish to force termination on that child process.
Ideally, I would like for that child process to act the same as if it had called ExitProcess, or as if a Ctrl+C was sent to its console (which calls ExitProcess from the default console control handler).
My solution so far has been the use of TerminateProcess to kill the child forcefully. This does force the child to terminate immediately, but unfortunately if that child spawned any children of its own they are left to run until their "natural" completion.
Is there a way to tell the child process to call ExitProcess, or to force all of the child's children to also terminate when TerminateProcess is called?
These external applications are beyond my control, and as such I can not modify them to provide a custom work-around.
Assume no knowledge of grand-child processes (names/pids/etc) that would allow me to manually call TerminateProcess on grand-child processes individually. Although this could be done by manually enumerating all processes, mapping process relationships, and tracking all processes, I do not consider this a valid solution except as the absolute last resort.
Thank you for your time.
You can use Job objects to kill all the processes as a unit. You create a job object via the CreateJobObject API, and assign a process to it with AssignProcessToJobObject. New processes created by a process in a job object belong to the same job object by default. Calling TerminateJobObject will terminate all associated processes in the job object.