How can I trigger an event twice in Python with multiprocessing

Viewed 53

So I wrote simple test code and I'm trying to execute event twice, but it only works once. After turn_left_e.set() I clear inner flag with turn_left_e.clear() (I also check it in code) and trying execute event second time, but it won't start. Here is my code:

import time
from multiprocessing import Event, Process

def check_light_dir(turn_left_e, turn_right_e):
    while True:
        time.sleep(2)
        var = random.randint(1, 10)
        print(f"var: {var}")
        if var < 5:
            print(f"turn_left_e before set(): {turn_left_e.is_set()}")
            turn_left_e.set()
        else:
            print(f"turn_right_e before set(): {turn_right_e.is_set()}")
            turn_right_e.set()


def turn_left(turn_left_e):
    turn_left_e.wait()
    print(f"turn_left_e after set(): {turn_left_e.is_set()}")
    print("Turning servo left")
    turn_left_e.clear()
    print(f"turn_left_e after clear(): {turn_left_e.is_set()}")


def turn_right(turn_right_e):
    turn_right_e.wait()
    print(f"turn_right_e after set(): {turn_right_e.is_set()}")
    print("Turning servo right")
    turn_right_e.clear()
    print(f"turn_right_e after clear(): {turn_right_e.is_set()}")


def test():
    turn_right_e = Event()
    turn_left_e = Event()

    check_light_dir_p = Process(target=check_light_dir, args=(turn_left_e, turn_right_e,))
    turn_right_p = Process(target=turn_right, args=(turn_right_e,))
    turn_left_p = Process(target=turn_left, args=(turn_left_e,))

    check_light_dir_p.start()
    turn_left_p.start()
    turn_right_p.start()

    check_light_dir_p.join()
    turn_right_p.join()
    turn_left_p.join()


if __name__ == "__main__":
    print("start")
    test()
    print("stop")

Output:

start

var: 4
turn_left_e before set(): False
turn_left_e after set(): True
Turning servo left
turn_left_e after clear(): False

var: 10
turn_right_e before set(): False
turn_right_e after set(): True
Turning servo right
turn_right_e after clear(): False

var: 9
turn_right_e before set(): False

var: 10
turn_right_e before set(): True

var: 2
turn_left_e before set(): False

var: 5
turn_right_e before set(): True

Process finished with exit code -1

So 1st and 2nd iterations servo moved. Funny part starts here: in 3rd iteration "before set()" was false and in 4th "before set()" was true! It seems to trigger event but didn't jump into it - there never was 2nd print "servo moved ..." and inner flags are infinitely set to True.

I don't understand why does it happens. I clear() events, so they should trigger as long as conditions is satisfied right?

1 Answers

The issue is, that functions turn_left and turn_right exits after first Event set and their processes end. Put while True: inside them:

...

def turn_left(turn_left_e):
    while True:              # <--------
        turn_left_e.wait()
        print(f"turn_left_e after set(): {turn_left_e.is_set()}")
        print("Turning servo left")
        turn_left_e.clear()
        print(f"turn_left_e after clear(): {turn_left_e.is_set()}")


def turn_right(turn_right_e):
    while True:              # <--------
        turn_right_e.wait()
        print(f"turn_right_e after set(): {turn_right_e.is_set()}")
        print("Turning servo right")
        turn_right_e.clear()
        print(f"turn_right_e after clear(): {turn_right_e.is_set()}")

...
Related