Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Unsolved Program doesn't completely quit

    General and Desktop
    5
    25
    3431
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • C
      Crag_Hack last edited by

      I have an interesting situation with my Qt program... in the installer I made with NSIS I have a page that detects if the program is running and if so prompts the user to close the program. Most of the time things proceed just fine however sometimes on my laptop the installer will detect the program running even though I quit it already. Nothing shows up in task manager however when I run tasklist from the command prompt after having quit the program I see:

      C:\Users\Owner>tasklist /FI "IMAGENAME eq ReplicatorNew.exe"
      
      Image Name                     PID Session Name        Session#    Mem Usage
      ========================= ======== ================ =========== ============
      ReplicatorNew.exe             8256 Console                    1         28 K
      

      If I run the program again I see:

      Image Name                     PID Session Name        Session#    Mem Usage
      ========================= ======== ================ =========== ============
      ReplicatorNew.exe             8256 Console                    1         28 K
      ReplicatorNew.exe             3040 Console                    1     50,940 K
      

      So something is sticking around after closing the program. Any ideas what's going on here? Thanks.

      JKSH kshegunov 2 Replies Last reply Reply Quote 0
      • JKSH
        JKSH Moderators @Crag_Hack last edited by

        @Crag_Hack said in Program doesn't completely quit:

        So something is sticking around after closing the program. Any ideas what's going on here?

        We can't tell without more details about your app. For example:

        1. How do you quit it?
        2. What does it do?
        3. Console app or GUI app?
        4. Do you use threads?

        Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

        1 Reply Last reply Reply Quote 4
        • C
          Crag_Hack last edited by Crag_Hack

          We can't tell without more details about your app. For example:

          1. How do you quit it?

          Just a normal window close for the qmainwindow.

          1. What does it do?

          The program closes as normal most of the time but sometimes a remnant is left that shows up in tasklist but not in task manager. Strange that with NSIS ${nsProcess::FindProcess} will detect the remnant but ${nsProcess::KillProcess} won't kill it (those are the NSIS way of detecting/killing running processes). So the installer thinks the program is still running and I can't kill it. Only a restart fixes.

          1. Console app or GUI app?

          GUI

          1. Do you use threads?

          Yes a worker thread and main GUI thread with no mutexes. When the program destructs it waits for the worker thread to stop. I can post the code if it would help.

          Thanks

          JKSH 1 Reply Last reply Reply Quote 0
          • JKSH
            JKSH Moderators @Crag_Hack last edited by JKSH

            @Crag_Hack said in Program doesn't completely quit:

            Just a normal window close for the qmainwindow.

            Can you show the code which ensures that your worker thread shuts down properly when you close the window?

            Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

            JonB 1 Reply Last reply Reply Quote 2
            • JonB
              JonB @JKSH last edited by

              @JKSH
              If & when the OP's program returns from sys.exit(app.exec()) (he can test if it does so) into main(), doesn't that call something like _exit() in the C runtime and I thought (haven't checked) that would terminate all threads, no?

              @Crag_Hack

              When the program destructs it waits for the worker thread to stop.

              And have you checked whether your program is actually spending time there waiting, and that's the reason it's still running sometimes?

              1 Reply Last reply Reply Quote 0
              • C
                Crag_Hack last edited by Crag_Hack

                Here 'tis the code. ReplicatorMainScreen is my QMainWindow (object name is mainScreen), replicator of type Replicator is my main logic object (derived from QWidget i did that back when I didn't know what I was doing and haven't gotten around to change it to deriving from QObject yet) and is instantiated from int main(), workerThread is obviously my worker thread, and worker is my worker thread QObject.

                void ReplicatorMainScreen::closeEvent(QCloseEvent *event)
                {
                    emit stopWork();
                    event->accept();
                }
                
                void ReplicatorMainScreen::setupBackend(Replicator *rep)
                {
                    connect(this,SIGNAL(stopWork()),rep,SLOT(stopWork()));
                }
                
                void Replicator::stopWork()
                {
                    quitting = true;
                    if (isBusy)
                        worker->stop(); //sets boolean cancel to true to let worker finish its work
                }
                
                Replicator::~Replicator()
                {
                    workerThread->quit();
                    workerThread->wait();
                }
                
                Replicator::Replicator(QWidget *parent) :
                    QWidget(parent)
                {
                    workerThread = new QThread(this);
                    workerThread->start();
                    worker = new Worker;
                    worker->moveToThread(workerThread);
                    mainScreen = new ReplicatorMainScreen;
                    setupWorker();
                    mainScreen->setupBackend(this);
                }
                
                void Replicator::setupWorker()
                {
                    connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
                }
                
                1 Reply Last reply Reply Quote 0
                • C
                  Crag_Hack last edited by

                  Also some minor details - I didn't run any backup jobs when the program didn't completely quit so the worker thread hadn't even been used except for being set up. The issue might be related to when the computer resumes from standby after the program was started during a prior session (I'd need more data to be sure). And the program remnant didn't show up in task manager only tasklist in the command prompt. Also the NSIS installer detected the remnant but wouldn't kill it.

                  JKSH 1 Reply Last reply Reply Quote 0
                  • JKSH
                    JKSH Moderators @Crag_Hack last edited by

                    @JonB said in Program doesn't completely quit:

                    And have you checked whether your program is actually spending time there waiting, and that's the reason it's still running sometimes?

                    +1 I suggest you check this, @Crag_Hack. One way is to add QDebug messages to your app, and view them using SysInternals DebugView (you might need to add filters first to suppress messages from other processes)

                    At a quick glance, your code seems to have added all the necessary things to clean up your thread properly. However, we can't rule out a race condition of some sort yet.

                    @Crag_Hack said in Program doesn't completely quit:

                    Also some minor details

                    Actually, these are major details which could contain important clues :)

                    I didn't run any backup jobs when the program didn't completely quit so the worker thread hadn't even been used except for being set up.

                    OK, this suggests that the problem isn't necessarily about a stuck thread.

                    The issue might be related to when the computer resumes from standby after the program was started during a prior session (I'd need more data to be sure).

                    Very possible. Definitely worth investigating.

                    And the program remnant didn't show up in task manager only tasklist in the command prompt.

                    I presume you mean it doesn't show up in the "Applications" tab. Does it show up in the "Processes" tab?

                    If I'm not mistaken, the app leaves the "Applications" tab when the last window is gone.

                    Also the NSIS installer detected the remnant but wouldn't kill it.

                    Ask the NSIS developers: Do they know of any situations which cause NSIS to be unable to kill a process?

                    @JonB said in Program doesn't completely quit:

                    If & when the OP's program returns from sys.exit(app.exec()) (he can test if it does so) into main(), doesn't that call something like _exit() in the C runtime and I thought (haven't checked) that would terminate all threads, no?

                    Sort of, but the issue is "Terminate" != "Proper shutdown". I'm not sure if abrupt termination lets the thread properly deinitialize any system resources that it's using.

                    Anyway, C++ Qt doesn't normally call exit(); we just let main() return naturally.

                    Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                    JonB 1 Reply Last reply Reply Quote 2
                    • C
                      Crag_Hack last edited by

                      @JKSH said in Program doesn't completely quit:

                      However, we can't rule out a race condition of some sort yet.

                      I only use signals and slots to communicate between the main GUI thread and worker thread, except for the stop function which uses an std::atomic_bool. Also all classes I use are reentrant except for QStrorageInfo but that's only used in the main thread. There might be others I'd have to look at the code but I was very careful to only use reentrant guys in the worker thread.

                      I presume you mean it doesn't show up in the "Applications" tab. Does it show up in the "Processes" tab?

                      If I'm not mistaken, the app leaves the "Applications" tab when the last window is gone.

                      In Windows 10 the two tabs are joined together in the processes tab in two separate lists. It doesn't show up in either.

                      JKSH 1 Reply Last reply Reply Quote 0
                      • JonB
                        JonB @JKSH last edited by JonB

                        @JKSH said in Program doesn't completely quit:

                        Anyway, C++ Qt doesn't normally call exit(); we just let main() return naturally.

                        My point is --- unless C++ start-up/shut-down is different from C in this respect which I doubt --- if you look at the C/C++ run-time code which calls your main() you will see that when that returns (return or just coming to the end of main()) into the runtime invoking code that code will call _exit(). Doesn't matter whether your code actually calls exit() or not, both ways end up calling _exit().

                        1 Reply Last reply Reply Quote 0
                        • JKSH
                          JKSH Moderators @Crag_Hack last edited by

                          @Crag_Hack said in Program doesn't completely quit:

                          I only use signals and slots to communicate between the main GUI thread and worker thread, except for the stop function which uses an std::atomic_bool. Also all classes I use are reentrant except for QStrorageInfo but that's only used in the main thread. There might be others I'd have to look at the code but I was very careful to only use reentrant guys in the worker thread.

                          In Windows 10 the two tabs are joined together in the processes tab in two separate lists. It doesn't show up in either.

                          I see. I'm out of ideas at this point, sorry.

                          All the best with your hunt!

                          It might be worth subscribing to the Interest mailing list and asking there -- Qt engineers are active on that list, and they might have further insight into the internals of your app.

                          @JonB said in Program doesn't completely quit:

                          My point is --- unless C++ start-up/shut-down is different from C in this respect which I doubt --- if you look at the C/C++ run-time code which calls your main() you will see that when that returns (return or just coming to the end of main()) into the runtime invoking code that code will call _exit(). Doesn't matter whether your code actually calls exit() or not, both ways end up calling _exit().

                          You're right, the C++ runtime behaves similarly to the C runtime.

                          Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                          1 Reply Last reply Reply Quote 0
                          • SGaist
                            SGaist Lifetime Qt Champion last edited by

                            Hi,

                            What does your worker object do ?
                            Are you sure it's stopping its work ?
                            Any system call in it ?

                            Interested in AI ? www.idiap.ch
                            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                            1 Reply Last reply Reply Quote 0
                            • C
                              Crag_Hack last edited by

                              @SGaist said in Program doesn't completely quit:

                              Hi,

                              What does your worker object do ?

                              File copy logic for file replicator based backup.

                              Are you sure it's stopping its work ?

                              I hadn't even run any backup job work when this error occurred.

                              Any system call in it ?

                              What do you mean by system call?

                              Thanks.

                              1 Reply Last reply Reply Quote 0
                              • SGaist
                                SGaist Lifetime Qt Champion last edited by

                                By "System call" I meant native low level function.

                                Interested in AI ? www.idiap.ch
                                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                1 Reply Last reply Reply Quote 0
                                • C
                                  Crag_Hack last edited by

                                  I've used a small spectrum of win API functions. Some requiring COM.

                                  1 Reply Last reply Reply Quote 0
                                  • SGaist
                                    SGaist Lifetime Qt Champion last edited by

                                    Did you check whether some of them needed to free some resource to properly stop ?

                                    Interested in AI ? www.idiap.ch
                                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                    1 Reply Last reply Reply Quote 0
                                    • C
                                      Crag_Hack last edited by

                                      I read the documentation thoroughly for all the functions. Weird thing is the intermittent nature of what's occurring and also that is happens after not having done any worker object work.

                                      1 Reply Last reply Reply Quote 0
                                      • kshegunov
                                        kshegunov Moderators @Crag_Hack last edited by kshegunov

                                        Get a stack trace from those processes that hang and post it here. (e.g. as described here)
                                        That's the best you can do to trace it, at least that is if it doesn't already hang in the debugger ...

                                        PS.
                                        Show us (parts) of your Worker class, as I see trouble brewing here.

                                        This:

                                        worker->stop(); //sets boolean cancel to true to let worker finish its work
                                        

                                        and this

                                        workerThread->quit();
                                        

                                        very rarely go hand in hand.

                                        Read and abide by the Qt Code of Conduct

                                        1 Reply Last reply Reply Quote 4
                                        • C
                                          Crag_Hack last edited by

                                          Since JKSH said he's out of ideas I opened another thread over at MSDN. See here. We ran process explorer and it showed the process as suspended. Also when trying to kill in process explorer we get access denied. Here is the threads info (no stack trace available). Also the process is not ReplicatorNew.exe it's Buddha Backup x64.exe (I was hesitant to get my name out there but concluded it doesn't' really matter).

                                          0_1532290551431_stacktrace.png

                                          kshegunov 1 Reply Last reply Reply Quote 0
                                          • C
                                            Crag_Hack last edited by Crag_Hack

                                            Here's the requested code with the previous code as well. Edited for brevity.

                                            void ReplicatorMainScreen::closeEvent(QCloseEvent *event)
                                            {
                                                emit stopWork();
                                                event->accept();
                                            }
                                            
                                            void ReplicatorMainScreen::setupBackend(Replicator *rep)
                                            {
                                                connect(ui->backupSelectedButton,SIGNAL(clicked(bool)),rep,SLOT(selectedBackup()));
                                                connect(this,SIGNAL(stopWork()),rep,SLOT(stopWork()));
                                                connect(ui->cancelButton,SIGNAL(clicked(bool)),rep,SLOT(cancelBackup()));
                                            }
                                            
                                            void Replicator::cancelBackup()
                                            {
                                                if (isBusy)
                                                    worker->stop();
                                            }
                                            
                                            void Replicator::stopWork()
                                            {
                                                quitting = true;
                                                if (isBusy)
                                                    worker->stop(); //sets boolean cancel to true to let worker finish its work
                                            }
                                            
                                            void Worker::stop() { cancel = true; } // cancel is std::atomic_bool
                                            
                                            void Replicator::selectedBackup()
                                            {
                                                isBusy = true;
                                                emit backup(jobList,simpleJobs);
                                            }
                                            
                                            void Worker::backup(QList<BackupJob> passJobs, QList<BackupJob> passSimpleJobs)
                                            {
                                                jobs = passJobs;
                                                simpleJobs = passSimpleJobs;
                                                startJobScans(); //these check for cancel condition and abort if true
                                                startJobBackups(); // this too
                                                emit backupFinished(JobType::Normal, cancel, errorsFound);
                                            }
                                            
                                            void Replicator::backupDone()
                                            {
                                                isBusy = false;
                                            }
                                            
                                            Replicator::~Replicator()
                                            {
                                                workerThread->quit();
                                                workerThread->wait();
                                            }
                                            
                                            Replicator::Replicator(QWidget *parent) :
                                                QWidget(parent)
                                            {
                                                workerThread = new QThread(this);
                                                workerThread->start();
                                                worker = new Worker;
                                                worker->moveToThread(workerThread);
                                                mainScreen = new ReplicatorMainScreen;
                                                setupWorker();
                                                mainScreen->setupBackend(this);
                                            }
                                            
                                            void Replicator::setupWorker()
                                            {
                                                connect(this, SIGNAL(backup(QList<BackupJob>,QList<BackupJob>)), worker, SLOT(backup(QList<BackupJob>,QList<BackupJob>)));
                                                connect(worker, SIGNAL(backupFinished(JobType,bool,bool)), this, SLOT(backupDone(JobType,bool,bool)));
                                                connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
                                            }
                                            
                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post