Fix-forward to avoid TSAN race on detached thread deletion
diff --git a/src/core/lib/gprpp/thd.h b/src/core/lib/gprpp/thd.h
index 0d94f2e..5631c5f 100644
--- a/src/core/lib/gprpp/thd.h
+++ b/src/core/lib/gprpp/thd.h
@@ -112,19 +112,22 @@
}
/// The destructor is strictly optional; either the thread never came to life
- /// and the constructor itself killed it or it has already been joined and
- /// the Join function kills it. The destructor shouldn't have to do anything.
- ~Thread() { GPR_ASSERT(impl_ == nullptr); }
+ /// and the constructor itself killed it, or it has already been joined and
+ /// the Join function kills it, or it was detached (non-joinable) and it has
+ /// run to completion and is now killing itself. The destructor shouldn't have
+ /// to do anything.
+ ~Thread() { GPR_ASSERT(!options_.joinable() || impl_ == nullptr); }
void Start() {
if (impl_ != nullptr) {
GPR_ASSERT(state_ == ALIVE);
state_ = STARTED;
impl_->Start();
- if (!options_.joinable()) {
- state_ = DONE;
- impl_ = nullptr;
- }
+ // If the Thread is not joinable, then the impl_ will cause the deletion
+ // of this Thread object when the thread function completes. Since no
+ // other operation is allowed to a detached thread after Start, there is
+ // no need to change the value of the impl_ or state_ . The next operation
+ // on this object will be the deletion, which will trigger the destructor.
} else {
GPR_ASSERT(state_ == FAILED);
}