Add a mutex to the thread object to protect its internal data. Prevent
making OS calls with a thread ID that has been terminated. This thread
ID can be reused by another thread, leading to undefined behavior if it
is used after termination.
Update the function Thread::join to use a semaphore to
determine when the thread finishes. This both avoids polling and
prevents a freed TCB from being accessed.
Thread-spawning constructors hide errors and may lead to complex
program state when a thread is declared.
The explicit Thread::start member function should be used to spawn
a thread.
- Allows threads to started separately from when they are declared,
avoiding the need to dynamically allocate threads at runtime.
- Allows multiple threads to join without forceful termination. Allowing
threads to synchronize on cleanup.