Search code examples
pythonloopsraspberry-piblockingnonblocking

Non-blocking infinite loop


I have a Raspberry pi with a Sense hat. I've made a binary clock that I want to display and keep updated on the Sense hat's display. However, I want the ability to toggle the clock on and off with joystick middle. Everything's working fine, apart from my clock's update-loop blocking any new input once it's started.

from sense_hat import SenseHat
from signal import pause

def show_clock():
    # clock-logic

def pushed_middle(event):
    while 1:
        show_clock()

sense = SenseHat()

sense.stick.direction_middle = pushed_middle
pause

I've been thinking about how to solve this. How to allow the script/clock to keep running and still accept new actions from the joystick. But once the while-loop starts, I'm stuck. I'm not sure what to google for. I've started looking into async/await, but that seem to be a Python 3.5+ feature, and my pi only has 2.7.9/3.4.2(I just sudo apt-get update/upgrade-ed). I've also tried moving the loop around in the program, but it's blocking everything no matter where I place it.

  • Is it a non-blocking (infinite) loop I'm looking for?
  • Is this what a game-/event-loop is?
  • Can I solve this with out using multiple threads(just curious, not a limitation if it's a must)?
  • Is this a general problem in "designing" infinite loops?
  • Can I approach this as a (reverse?) race condition? I was thinking about maybe using a semaphore as some kind of tool to not block, but I'm not sure.

Solution

  • I solved it by using a global variable:

    from sense_hat import SenseHat
    from signal import pause
    
    def show_clock():
        global clock_is_on
    
        while clock_is_on:  # clock-loop
            # clock-logic
            # ...
    
            events = sense.stick.get_events()
    
            for event in events:
                if event.direction == "middle" and event.action == "pressed":
                  clock_is_on = False
    
            time.sleep(1) # only need to update clock once every second
    
    def pushed_middle(event):
        if not clock_is_on:
            clock_is_on = True
            show_clock()
    
    sense = SenseHat()
    
    clock_is_on = False
    
    sense.stick.direction_middle = pushed_middle
    pause()