@@ -492,7 +492,7 @@ class thread {
492
492
// / Default constructor.
493
493
// / Construct a @c thread object without an associated thread of execution
494
494
// / (i.e. non-joinable).
495
- thread () : mHandle (0 ), mNotAThread ( true )
495
+ thread () : mHandle (0 ), mJoinable ( false )
496
496
#if defined(_TTHREAD_WIN32_)
497
497
, mWin32ThreadID (0 )
498
498
#endif
@@ -554,7 +554,7 @@ class thread {
554
554
private:
555
555
native_handle_type mHandle ; // /< Thread handle.
556
556
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?
558
558
#if defined(_TTHREAD_WIN32_)
559
559
unsigned int mWin32ThreadID ; // /< Unique thread ID (filled out by _beginthreadex).
560
560
#endif
@@ -871,7 +871,12 @@ inline void * thread::wrapper_function(void * aArg)
871
871
872
872
// The thread is no longer executing
873
873
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
875
880
876
881
// The thread is responsible for freeing the startup information
877
882
delete ti;
@@ -891,8 +896,8 @@ inline thread::thread(void (*aFunction)(void *), void * aArg)
891
896
ti->mArg = aArg;
892
897
ti->mThread = this ;
893
898
894
- // The thread is now alive
895
- mNotAThread = false ;
899
+ // Mark thread as joinable
900
+ mJoinable = true ;
896
901
897
902
// Create the thread
898
903
#if defined(_TTHREAD_WIN32_)
@@ -905,9 +910,10 @@ inline thread::thread(void (*aFunction)(void *), void * aArg)
905
910
// Did we fail to create the thread?
906
911
if (!mHandle )
907
912
{
908
- mNotAThread = true ;
913
+ mJoinable = false ;
909
914
delete ti;
910
915
}
916
+
911
917
}
912
918
913
919
inline thread::~thread ()
@@ -926,28 +932,37 @@ inline void thread::join()
926
932
#elif defined(_TTHREAD_POSIX_)
927
933
pthread_join (mHandle , NULL );
928
934
#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 ;
929
942
}
930
943
}
931
944
932
945
inline bool thread::joinable () const
933
946
{
934
947
mDataMutex .lock ();
935
- bool result = ! mNotAThread ;
948
+ bool result = mJoinable ;
936
949
mDataMutex .unlock ();
937
950
return result;
938
951
}
939
952
940
953
inline void thread::detach ()
941
954
{
955
+ // TODO: Attempting to detach a non-joinable thread should throw.
956
+ // https://en.cppreference.com/w/cpp/thread/thread/detach
942
957
mDataMutex .lock ();
943
- if (! mNotAThread )
958
+ if (mJoinable )
944
959
{
945
960
#if defined(_TTHREAD_WIN32_)
946
961
CloseHandle (mHandle );
947
962
#elif defined(_TTHREAD_POSIX_)
948
963
pthread_detach (mHandle );
949
964
#endif
950
- mNotAThread = true ;
965
+ mJoinable = false ;
951
966
}
952
967
mDataMutex .unlock ();
953
968
}
0 commit comments