Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Stopping a running QProcess slows down GUI (Windows)
Qt 6.11 is out! See what's new in the release blog

Stopping a running QProcess slows down GUI (Windows)

Scheduled Pinned Locked Moved Unsolved Qt for Python
10 Posts 4 Posters 1.5k Views 1 Watching
  • 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.
  • P Offline
    P Offline
    PyMan
    wrote on last edited by
    #1

    Hello.
    I have a GUI application that launches a qprocess. This qprocess calls up a long-running console program in the background which spits out a bunch of stdout. When there is something new from that qprocess on stdout, it will emit a signal with that stdout line and is slotted by the GUI and displayed in a Text Browser widget. It works great if I just let it run and exit on its own. But if I try to interrupt the qprocess with a stop button, which sends a .kill() command to the qprocess, it will severely slow down my GUI. The GUI still works, its just really slow. Text fields are slow to respond. Even dragging the GUI window around is choppy and skips around. If I do too many things in the GUI in this condition, it can crash the GUI; like if I mouse over the menu bar items and quickly move the mouse to drag the MainWindow and then go and click some text field, it will freeze and grey out the whole GUI like it is trying to buffer all my functions, and it may follow through with the last action or it may just crash and close.

    I narrowed it down to the qprocess being killed.

    I wrote a side program to monitor PIDs and confirm that when I press the stop button, the process indeed is killed and the GUI is the only pid running. So somehow a killed off qprocess causes the GUI to jam up. Not sure how to get over this. Thoughts?

    jsulmJ 1 Reply Last reply
    0
    • P PyMan

      Hello.
      I have a GUI application that launches a qprocess. This qprocess calls up a long-running console program in the background which spits out a bunch of stdout. When there is something new from that qprocess on stdout, it will emit a signal with that stdout line and is slotted by the GUI and displayed in a Text Browser widget. It works great if I just let it run and exit on its own. But if I try to interrupt the qprocess with a stop button, which sends a .kill() command to the qprocess, it will severely slow down my GUI. The GUI still works, its just really slow. Text fields are slow to respond. Even dragging the GUI window around is choppy and skips around. If I do too many things in the GUI in this condition, it can crash the GUI; like if I mouse over the menu bar items and quickly move the mouse to drag the MainWindow and then go and click some text field, it will freeze and grey out the whole GUI like it is trying to buffer all my functions, and it may follow through with the last action or it may just crash and close.

      I narrowed it down to the qprocess being killed.

      I wrote a side program to monitor PIDs and confirm that when I press the stop button, the process indeed is killed and the GUI is the only pid running. So somehow a killed off qprocess causes the GUI to jam up. Not sure how to get over this. Thoughts?

      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @PyMan Did you debug your app to see what happens?
      How exactly do you kill the process? You should show relevant code.

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      P 1 Reply Last reply
      1
      • jsulmJ jsulm

        @PyMan Did you debug your app to see what happens?
        How exactly do you kill the process? You should show relevant code.

        P Offline
        P Offline
        PyMan
        wrote on last edited by PyMan
        #3

        @jsulm yea. Here is what I could strip down but basically represents the areas that represent generating the qprocess and stopping the qprocess.

        Here is how the qprocess is generated:

        def launch_cmd(self):
            '''Launches the qprocess and assigns slots to signals.''
            self.cli_process = QProcess()
            self.cli_process.readyReadStandardOutput.connect(self.handle_stdout)
            # self.cli_process.readyReadStandardError.connect(self.handle_stderr)
            self.cli_process.start("myprog.exe", ["run", "all", "--debug"])
        

        Here is the stop slot function, which is actually in a thread. I haven't yet tried making this as a slot inside the GUI portion of code code, its in the Thread class. cli_process was passed into the thread class for some reason.

        def stop(self):
            '''Stops the thread and does some housekeeping'''
            print("Stop detected")
            self.abort_flag = True
            self.is_running = False
            try:
                self.cli_process.kill()
                #if self.cli_process.processId():
                    #os.kill(self.cli_process.processId(), signal.SIGINT)
            except:
                print(f"[{datetime.now()}]: Warning, cli process not killed...continuing headless.")
                else: pass
        

        Thanks for taking a look!

        jsulmJ 1 Reply Last reply
        0
        • P Offline
          P Offline
          PyMan
          wrote on last edited by
          #4

          Is there a way to use QProcess.write() to send a Ctrl+C and allow the QProcess to exit on its own? That would solve the problem. Literally I have narrowed it down to the .kill() command, if I can avoid that, I'll be golden.

          JonBJ 1 Reply Last reply
          0
          • P PyMan

            @jsulm yea. Here is what I could strip down but basically represents the areas that represent generating the qprocess and stopping the qprocess.

            Here is how the qprocess is generated:

            def launch_cmd(self):
                '''Launches the qprocess and assigns slots to signals.''
                self.cli_process = QProcess()
                self.cli_process.readyReadStandardOutput.connect(self.handle_stdout)
                # self.cli_process.readyReadStandardError.connect(self.handle_stderr)
                self.cli_process.start("myprog.exe", ["run", "all", "--debug"])
            

            Here is the stop slot function, which is actually in a thread. I haven't yet tried making this as a slot inside the GUI portion of code code, its in the Thread class. cli_process was passed into the thread class for some reason.

            def stop(self):
                '''Stops the thread and does some housekeeping'''
                print("Stop detected")
                self.abort_flag = True
                self.is_running = False
                try:
                    self.cli_process.kill()
                    #if self.cli_process.processId():
                        #os.kill(self.cli_process.processId(), signal.SIGINT)
                except:
                    print(f"[{datetime.now()}]: Warning, cli process not killed...continuing headless.")
                    else: pass
            

            Thanks for taking a look!

            jsulmJ Offline
            jsulmJ Offline
            jsulm
            Lifetime Qt Champion
            wrote on last edited by
            #5

            @PyMan said in Stopping a running QProcess slows down GUI (Windows):

            which is actually in a thread

            Why a thread?
            If the app you're starting as another process is your application you could let it read from stdin and then write to it via QProcess to tell it to terminate.
            Or simply use https://doc.qt.io/qt-6/qprocess.html#terminate

            It is also still not clear what happens after calling kill (why your app is becoming slow).

            https://forum.qt.io/topic/113070/qt-code-of-conduct

            P 1 Reply Last reply
            0
            • P PyMan

              Is there a way to use QProcess.write() to send a Ctrl+C and allow the QProcess to exit on its own? That would solve the problem. Literally I have narrowed it down to the .kill() command, if I can avoid that, I'll be golden.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #6

              @PyMan said in Stopping a running QProcess slows down GUI (Windows):

              Is there a way to use QProcess.write() to send a Ctrl+C and allow the QProcess to exit on its own?

              I don't think that would work. I think it requires a Ctrl+C on the attached console, not character 3 on its standard input.

              We don't know what your myprog.exe run all --debug does or how myprog.exe behaves. I would begin by trying with some other command (not yours) and see how it behaves.

              One point: your try ... except should be a waste of time, Qt code (e.g. QProcess.kill()) does not raise exceptions.

              1 Reply Last reply
              2
              • jsulmJ jsulm

                @PyMan said in Stopping a running QProcess slows down GUI (Windows):

                which is actually in a thread

                Why a thread?
                If the app you're starting as another process is your application you could let it read from stdin and then write to it via QProcess to tell it to terminate.
                Or simply use https://doc.qt.io/qt-6/qprocess.html#terminate

                It is also still not clear what happens after calling kill (why your app is becoming slow).

                P Offline
                P Offline
                PyMan
                wrote on last edited by
                #7

                @jsulm I have multiple threads running. Each thread has an associated call to the external myprog.exe and needs to read the STDOUT of it in order to make calculations.

                the myprog.exe is not my code, it is a client's program. That program connects to a com port. There are 6 total com ports that the myprog.exe works with asynchronously. This is why the QProcess termination is controlled by a thread. It is controlled by a thread because the user needs to be able stop that individual myprog.exe called that is connected to that com port. I do not have control of what goes between the comport and myprog.exe. Like I said, when it runs to completion and exits gracefully, it doesn't affect the GUI. I will try to do a minimal viable mockup to post here. But I dont want to overcomplicate.

                That said, I tried the QProcess.terminate() and it does nothing. Reading the doc, I see 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().

                So my guess is myprog.exe does not handle WM_CLOSE. I could ask the client to put that feature in I guess, but they may look at me sideways. Ctrl+C is how we kill it normally. TKinter does not have this issue. I can send a Ctrl+C to it via subprocess and it has no affect on the TKInter GUI.

                I don't know why the QProcess.kill() affects the GUI. I have taken the kill command out of the thread's stop() method and put it directly in the main application code where the stop button slot is, and it does the same exact thing. I can see it does successfully kill the QProcess.

                SGaistS 1 Reply Last reply
                0
                • P PyMan

                  @jsulm I have multiple threads running. Each thread has an associated call to the external myprog.exe and needs to read the STDOUT of it in order to make calculations.

                  the myprog.exe is not my code, it is a client's program. That program connects to a com port. There are 6 total com ports that the myprog.exe works with asynchronously. This is why the QProcess termination is controlled by a thread. It is controlled by a thread because the user needs to be able stop that individual myprog.exe called that is connected to that com port. I do not have control of what goes between the comport and myprog.exe. Like I said, when it runs to completion and exits gracefully, it doesn't affect the GUI. I will try to do a minimal viable mockup to post here. But I dont want to overcomplicate.

                  That said, I tried the QProcess.terminate() and it does nothing. Reading the doc, I see 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().

                  So my guess is myprog.exe does not handle WM_CLOSE. I could ask the client to put that feature in I guess, but they may look at me sideways. Ctrl+C is how we kill it normally. TKinter does not have this issue. I can send a Ctrl+C to it via subprocess and it has no affect on the TKInter GUI.

                  I don't know why the QProcess.kill() affects the GUI. I have taken the kill command out of the thread's stop() method and put it directly in the main application code where the stop button slot is, and it does the same exact thing. I can see it does successfully kill the QProcess.

                  SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  @PyMan hi,

                  Out of curiosity, since you are mentioning serial ports, why not use QSerialPort and handle that part directly in your application ?

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

                  P 1 Reply Last reply
                  0
                  • SGaistS SGaist

                    @PyMan hi,

                    Out of curiosity, since you are mentioning serial ports, why not use QSerialPort and handle that part directly in your application ?

                    P Offline
                    P Offline
                    PyMan
                    wrote on last edited by
                    #9

                    @SGaist said in Stopping a running QProcess slows down GUI (Windows):

                    part directly in your application

                    Yes I would normally do that, but myprog.exe is doing that and I have no control over myprog.exe. There are things under the hood that I'm not consigned to do. This is strictly a GUI project and launches and controls an approved application, several instances of it actually.

                    1 Reply Last reply
                    0
                    • P Offline
                      P Offline
                      PyMan
                      wrote on last edited by
                      #10

                      @JonB said in Stopping a running QProcess slows down GUI (Windows):

                      k. I think it requires a Ctrl+C on the attached console, not character 3 on its standard inp

                      I confirmed this, you are exactly correct. Since QProcess.kill() can't send anything, I tried os.kill() because I can send signals. I experimented with

                      os.kill(QProcess.processID, signal.CTRL_C_EVENT)
                      

                      and that sends the ctrl+c to the upper python console running the whole show and force quits the entire GUI. :(

                      I consider this a bit buggy, I mean QProcess.kill() is working, the only issue with it is what's happening to the GUI after the fact. The GUI still works to some extent, but definitely a slowdown is happening and doesn't like me to click things too fast. I'll try to get a demo together. Something about QProcess is intimately tied to the GUI, maybe its because the ungraceful end of the QProcess affected how the PyQT GUI is dealing with a hanging signal out there that just abruptly ended? How does that signal / slot mechanism work under the hood? Maybe the PyQT GUI is trying to poll a process that no longer exists? I think this is bugreport-worthy.

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved