I am writing a tkinter app and is using threads for performance (computing-intensive tasks)
Threads need to be joined, but I am lazy.
I don't really like the idea of constantly checking if a thread is alive.
I created a class to handle join automatically when the job is done. However, it still has the risk of having race conditions (that's what GPT said)
class RunInThreadHandler(ctk.CTkFrame):
def __init__(self, master: ctk.CTkBaseClass,
target: Callable,
args: tuple = (),
func_end_callback: Optional[Callable] = None,
kwargs: Optional[dict[str, Any]] = None):
super().__init__(master)
self._func: Callable = target
self._args: tuple = args
self._kwargs: dict[str, Any] = kwargs if kwargs is not None else {}
self._func_end_callback: Optional[Callable] = func_end_callback
self._thread: Optional[Thread] = Thread(target=self._thread_func)
self._thread.start()
def _thread_func(self):
try:
self._func(*self._args, **self._kwargs)
except BaseException as exc:
print(exc)
self.after(1000, self._thread.join)
if self._func_end_callback is not None:
self.after(1000, self._func_end_callback)
Usage:
RunInThreadHandler(self, target=foo) # runs foo in thread on the spot
Q: Any better ways?
Typically, the purpose of calling join()
is for the creator of the thread to verify that the thread execution has completed or in cases, non-termination, to force terminate the thread and performs the necessary cleanups.
So, if the user of RunInThreadHandler
is not interested in waiting for the thread to complete for the reasons above, then I don't see any point in calling join()
. Moreover, as you have pointed out yourself, the way you write the code will cause the code to join itself, which will cause your thread to never terminate.