-
-
Notifications
You must be signed in to change notification settings - Fork 65
Description
#975 has introduced a race condition between the NamedThread constructor and NamedThread::getCurrentThreadName().
Lines 37 to 42 in fe520a3
| template <class F, class... Args> | |
| NamedThread(const std::string& name, F&& f, Args&&... args) | |
| : NamedThread(name) | |
| { | |
| thread_ = std::thread(std::forward<F>(f), std::forward<Args>(args)...); | |
| } |
Lines 67 to 87 in fe520a3
| std::string NamedThread::getCurrentThreadName() | |
| { | |
| std::lock_guard<std::mutex> lock(mutex_); | |
| const auto curThreadId = std::this_thread::get_id(); | |
| const auto it = threadId2NameMap_.find(curThreadId); | |
| if ( it != threadId2NameMap_.end() ) | |
| return it->second; | |
| for (const auto nt : namedThreads_) { | |
| if ( nt->thread_.get_id() == curThreadId ) { | |
| threadId2NameMap_[curThreadId] = nt->name_; | |
| return nt->name_; | |
| } | |
| } | |
| std::ostringstream newEntryName; | |
| newEntryName << "thread#" << threadCounter_++; | |
| threadId2NameMap_[curThreadId] = newEntryName.str(); | |
| return newEntryName.str(); | |
| } |
NamedThread::getCurrentThreadName() may be called from the thread (that already started executing) before the assignment to thread_ in the NamedThread constructor has taken place. Then the query to the thread id (nt->thread_.get_id()) on such a thread will not return the correct id, and the end result will be that a new (numbered) thread name will be synthesized for that thread. From that point onward, concurrency orchestration via log_debug() (which relies on correct thread names) breaks and typically results in a deadlock (for example, https://github.com/openzim/libzim/actions/runs/14811515862/job/41586752155?pr=982).