I am writing a small Python script that makes heavy use of threads / multiple processes and I came across an interesting race condition that I cannot find an explanation for. I have a background process that plays a song that the user can skip or that can end on it's own, in both these cases I need to fire a callback to say it has ended.
Below is a psuedo code sample demonstrating the problem :
import threading, subprocess def play_song(song_name, callback) : stop_any_previous_songs() play_song_in_subprocess_then_call(callback) def main(self) : while True : music_stopped = threading.Event() def play_callback() : # say that the song stopped music_stopped.set() #Assume that the thread is actually a daemon threading.Thread(target=play_song, \ args=(get_next_song(), play_callback)\ .start() while not music_stopped.is_set() and user_not_interrupted() : # Spin pass if music_stopped.is_set() : # End of song reached, play the next song continue else : # User input from some source process_user_input()
The problem is that when starting a new song after a previous song had played the
play_callback would be called as a result of the
stop_any_previous_songs() call. When called the
play_callback would call
set on the
music_stopped Event for the next song.
So my question is when the
play_callback function is called is it merely going to the enclosing scope and looking for an object with the name `music_stopped'? Or is the underlying cause something else?