@@ -492,7 +492,7 @@ class thread {
492492 // / Default constructor.
493493 // / Construct a @c thread object without an associated thread of execution
494494 // / (i.e. non-joinable).
495- thread () : mHandle (0 ), mNotAThread ( true )
495+ thread () : mHandle (0 ), mJoinable ( false )
496496#if defined(_TTHREAD_WIN32_)
497497 , mWin32ThreadID (0 )
498498#endif
@@ -554,7 +554,7 @@ class thread {
554554 private:
555555 native_handle_type mHandle ; // /< Thread handle.
556556 mutable mutex mDataMutex ; // /< Serializer for access to the thread private data.
557- bool mNotAThread ; // /< True if this object is not a thread of execution.
557+ bool mJoinable ; // /< Is the thread joinable?
558558#if defined(_TTHREAD_WIN32_)
559559 unsigned int mWin32ThreadID ; // /< Unique thread ID (filled out by _beginthreadex).
560560#endif
@@ -871,7 +871,12 @@ inline void * thread::wrapper_function(void * aArg)
871871
872872 // The thread is no longer executing
873873 lock_guard<mutex> guard (ti->mThread ->mDataMutex );
874- ti->mThread ->mNotAThread = true ;
874+
875+ // On POSIX, we allow the thread to be joined even after execution has finished.
876+ // This is necessary to ensure that thread-local memory can be reclaimed.
877+ #if defined(_TTHREAD_WIN32_)
878+ ti->mThread ->mJoinable = false ;
879+ #endif
875880
876881 // The thread is responsible for freeing the startup information
877882 delete ti;
@@ -891,8 +896,8 @@ inline thread::thread(void (*aFunction)(void *), void * aArg)
891896 ti->mArg = aArg;
892897 ti->mThread = this ;
893898
894- // The thread is now alive
895- mNotAThread = false ;
899+ // Mark thread as joinable
900+ mJoinable = true ;
896901
897902 // Create the thread
898903#if defined(_TTHREAD_WIN32_)
@@ -905,9 +910,10 @@ inline thread::thread(void (*aFunction)(void *), void * aArg)
905910 // Did we fail to create the thread?
906911 if (!mHandle )
907912 {
908- mNotAThread = true ;
913+ mJoinable = false ;
909914 delete ti;
910915 }
916+
911917}
912918
913919inline thread::~thread ()
@@ -926,28 +932,37 @@ inline void thread::join()
926932#elif defined(_TTHREAD_POSIX_)
927933 pthread_join (mHandle , NULL );
928934#endif
935+
936+ // https://linux.die.net/man/3/pthread_join states:
937+ //
938+ // Joining with a thread that has previously been joined results in undefined behavior.
939+ //
940+ // We just allow a thread to be joined once.
941+ mJoinable = false ;
929942 }
930943}
931944
932945inline bool thread::joinable () const
933946{
934947 mDataMutex .lock ();
935- bool result = ! mNotAThread ;
948+ bool result = mJoinable ;
936949 mDataMutex .unlock ();
937950 return result;
938951}
939952
940953inline void thread::detach ()
941954{
955+ // TODO: Attempting to detach a non-joinable thread should throw.
956+ // https://en.cppreference.com/w/cpp/thread/thread/detach
942957 mDataMutex .lock ();
943- if (! mNotAThread )
958+ if (mJoinable )
944959 {
945960#if defined(_TTHREAD_WIN32_)
946961 CloseHandle (mHandle );
947962#elif defined(_TTHREAD_POSIX_)
948963 pthread_detach (mHandle );
949964#endif
950- mNotAThread = true ;
965+ mJoinable = false ;
951966 }
952967 mDataMutex .unlock ();
953968}
0 commit comments