Skip to content

Race condition in NamedThread #983

@veloman-yunkan

Description

@veloman-yunkan

#975 has introduced a race condition between the NamedThread constructor and NamedThread::getCurrentThreadName().

libzim/src/namedthread.h

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)...);
}

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).

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions