class instance as process within kivy app: kivy app gets stuck
Question: I do have an interface to store settings and to start a process. However, I
cannot close everything once the process starts because kivy gets stuck after
calling `process.run`. Here is a minimal example:

    
    
    #! /usr/bin/env python
    
    """
    Activate the touch keyboard. It is important that this part is on top
    because the global config should be initiated first.
    """
    from kivy.config import Config
    Config.set('kivy', 'keyboard_mode', 'multi')
    
    # the main app
    from kivy.app import App
    
    # The Builder is used to define the main interface.
    from kivy.lang import Builder
    
    # The start screen is defined as BoxLayout
    from kivy.uix.boxlayout import BoxLayout
    
    # The pHBot class
    from phbot import pHBot
    
    # The pHBot is defined as process. Otherwise it would not be possible to use the close button.
    from multiprocessing import Process, Queue
    
    
    
    # Definition of the Main interface
    Builder.load_string('''
    <Interface>:
        orientation: 'vertical'
        Button:
            text: 'Run pH-Bot'
            font_size: 40
            on_release: app.run_worker()
        Button:
            text: 'Close pH-Bot'
            font_size: 40
            on_release: app.stop_phbot()
    ''')
    
    
    # Interface as a subclass of BoxLayout without any further changes. This part is used by kivy.
    class Interface(BoxLayout):
        pass
    
    
    class SettingsApp(App):
        """
        The settings App is the main app of the pHBot application. It is initiated by kivy and contains the functions
        defining the main interface.
        """
    
        def build(self):
            """
            This function initializes the app interface and has to be called "build(self)". It returns the user interface
            defined by the Builder.
            """
    
            # A queque for the control all processes.
            self.qu_stop = Queue()
    
            # returns the user interface defined by the Builder
            return Interface()
    
        def run_worker(self):
            """
            The pHBot application is started as a second process.
            """
            bot = pHBot(self.qu_stop)
            phbot = Process(target=bot.ph_control())
            # start the process
            phbot.run()
    
        def stop_phbot(self):
            self.qu_stop.put('STOP')
    
    if __name__ == '__main__':
        SettingsApp().run()
    

The second class is within a file called `phbot.py`:

    
    
    import time
    
    
    class pHBot:
    
        def __init__(self,  qu_stop_in):
            self.qu_stop_in = qu_stop_in
    
        def ph_control(self):
    
            while True:
                if self.qu_stop_in.full():
                    if self.qu_stop_in.get() == 'STOP':
                        break
                print('Back and forth forever ...')
                time.sleep(2)
    

What am I missing here ?


Answer: Note that a `Process` is started with
[`start()`](https://docs.python.org/2/library/multiprocessing.html#process-
and-exceptions). Calling `run()` really immediately launches the worker from
the same process, and thus it is blocking. The relevant lines in `run_worker`
should therefore be:

    
    
        bot = pHBot(self.qu_stop)
        phbot = Process(target=bot.ph_control)
        # start the process
        phbot.start()
    

In addition, in your worker, don't check whether the `Queue` is full. Rather,
do a non-blocking `get` and handle the `Queue.Empty` exception:

    
    
    import Queue
    ...
        def ph_control(self):
    
            while True:
                try:
                    item = self.qu_stop_in.get(False)
                    if item == 'STOP':
                        break
                except Queue.Empty:
                    print "Nothing to see"
                print('Back and forth forever ...')
                time.sleep(2)
    

