user1833028
user1833028

Reputation: 943

I can only resolve these race conditions in python by hanging the program or adding timers

I have a very simple example of decorators and multithreading. However, there are several issues I can't resolve:

1.) There is a race condition at change_print_event_handler(). The "PRINT" event before it always seems to get called after it executes.
2.) The print event "this may no longer matter to you" does not get called at all, unless:
a.) add event_loop_thread.join() to the end of the thread.
b.) add a sleep time to the end to the event joiner function
c.) Make the event_loop_thread = threading.Thread(target=event_loop, daemon=True) line say daemon = false.

All of these "unless" solutions, however, cause the program to hang indefintely.

I would appreciate any explanation of how this might be addressed, either by restructuring the program entirely or by adding or changing a few lines.

import threading
import queue
import time

event_queue = queue.Queue();
event_handlers = {}

def register_event(event_type):
    def decorator(func):
        event_handlers[event_type] = func
        return func
    return decorator

@register_event("PRINT")
def handle_printer_event(message):
    print(f"Print Event: {message}")
    
@register_event("ALERT")
def handle_alert_event(message):
    print(f"Alert! {message}")

def event_loop():
    while True:
        try:
            #event_type, message = event_queue.get(timeout=1)
            event_type, message = event_queue.get(timeout=1)
            if event_type in event_handlers:
                event_handlers[event_type](message)
            else:
                print(f"No handler for event type: {event_type}")
        except queue.Empty:
            pass
                
def add_events():
    time.sleep(1)
    event_queue.put(("PRINT", "This is a print event"))
    time.sleep(2)
    event_queue.put(("ALERT", "This is an alert event"))
    time.sleep(1)
    event_queue.put(("UNKNOWN", "This event has no handler"))
    time.sleep(1)
    event_queue.put(("PRINT", "This is another print event"))
    change_print_event_handler()
    time.sleep(1)
    event_queue.put(("PRINT", "this may no longer matter to you"))
    #time.sleep(1)
    
def change_print_event_handler():
    def game_over_handler(message):
        print("Game over")
    event_handlers["PRINT"] = game_over_handler
    
event_loop_thread = threading.Thread(target=event_loop, daemon=True)
event_loop_thread.start()

event_adder_thread = threading.Thread(target=add_events, daemon=True)
event_adder_thread.start()

event_adder_thread.join()
#event_loop_thread.join()

Upvotes: 0

Views: 26

Answers (0)

Related Questions