Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is it not possible to wait for a Qt process to finish in a static destructor?

Tags:

c++

qt

The following piece of code starts a process that takes one second to finish, and subsequently waits for that process to finish before exiting. For some reason, the following code hangs in p->waitForFinished() even though the process did finish.

#include <QtCore/QProcess>    

class A
{
  public:
    A():
        p(0)
    {
    }

    ~A()
    {
        p->waitForFinished();
        delete p;
    }

    void start()
    {
        p = new QProcess(0);
        p->start("sleep 1");
    }

    QProcess *p;
};

int main(void)
{
  static A a;
  a.start();

  return 0;
}

However, as soon as a is not declared statically, but as follows:

A a;

the waitForFinished() call succeeds. Is this a Qt bug, or is this expected behavour? My suspicion is that some kind of logic required to detect whether an application successfully finished is already destroyed once the destructor of A is called.

like image 912
Ton van den Heuvel Avatar asked Jan 03 '13 20:01

Ton van den Heuvel


1 Answers

You have tried to clean up the thread created by QProcess two different ways at the same time, so this is a bug in your program.

You've detached the thread by returning from main (which terminates all threads in the process, detaching them if they are joinable).

And you've cleaned up the QProcess thread by joining it through waitForFinished.

You can detach a thread or you can join it, but you can't do both, even indirectly. Apparently, the detach wins, and the join hangs.

Most likely this is because QProcess uses its own termination signal rather than the one built into the threading library. So the return from main terminates the thread before it can send that termination signal, leaving the waitForFinished function to wait for a signal that will never be sent.

As a general rule, threads should not be created in constructors nor cleaned up in destructors. This is primarily because the timing of these operations requires more explicit control than is possible. And they should never be created before main starts nor cleaned up after main returns -- again because you need to control the context in which these things happen.

like image 138
David Schwartz Avatar answered Oct 31 '22 21:10

David Schwartz